java 多線程和同步
java 多線程
多線程的作用
- 提高資源的利用率
如果當執行單線程的程序時,程序發生阻塞情況,此時的CPU會處於空閒狀態;而多線程中,當有一個線程發生阻塞時,CPU會執行其他的進程,從而提高了資源的利用率。 - 簡化編程
如果編寫一個讀取和操作文件的程序時,必須跟蹤每個文件的讀取和處理狀態,相反我們可以創建兩個線程,每個線程只讀取或處理單個文件,這樣不僅可以提高磁盤的利用率,還容編寫。、
創建自定義線程的兩種方式
- 自定義線程類,繼承Thread類,重寫run方法
創建自定義線程對象,直接調用start方法,開啓線程
class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("繼承Thread類自定義線程類");
}
}
}
//在main方法中
MyThread1 myThread1 = new MyThread1();
myThread1.start();
- 自定義線程類,遵從Runnable接口
使用自定義遵從接口Runnable實現類對象,作爲Thread構造方法參數,藉助於Thread類對象和start方法,開啓線程
class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("遵從Runnable接口實現自定義線程類");
}
}
}
//在main方法中
Thread thread = new Thread(new MyThread2());
// 藉助於Thread類內的start方法開啓線程
thread.start();
Thread 中的方法
構造方法名 | 作用 |
---|---|
Thread() | 無目標,無指定名字 |
Thread(Runnable target); | 創建線程對象的過程中,使用Runnable接口的實現類 |
Thread(String name); | 無目標,有名字 |
Thread(Runnable target, String name); | 使用Runnable接口實現類對象,作爲執行目標,並且指定name作爲線程名 |
成員方法 | 作用 |
---|---|
void setName(String name);String getName(); | name的getter 和 Setter 方法 |
void setPriority(int Priority); | 設置線程的優先級 [1 ~ 10] |
int getPriority(); | 獲取線程優先級 |
void start(); | 啓動線程對象 |
public static void sleep(int ms); | 對應進程進行休眠操作。單位毫秒 |
public static Thread currentThread(); | 獲取當前所處代碼塊對應的線程對象 |
線程安全問題和解決方案
舉例來說,一個電影有100張票,有3個出售平臺,實現這個案例
class SingleThread implements Runnable {
private static int ticket = 100;
@Override
public void run() {
while (true) {
// a
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "售出了" + ticket + "張票");
ticket -= 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "售罄!");
break;
}
//b
}
}
}
//在main方法中
Thread thread1 = new Thread(new SingleThread(), "淘票票");
Thread thread2 = new Thread(new SingleThread(), "貓眼");
Thread thread3 = new Thread(new SingleThread(), "美團");
thread1.start();
thread2.start();
thread3.start();
但是在運行的結果中,我們會發現同一張票被出售了不止一次,爲了解決這種問題,我們引入了“鎖”機制。
synchronized
while (true) {
synchronized("鎖") {
//此處是上面的ab範圍內的代碼
}
}
通過這種方式我們可以解決上面出現的問題
三種加鎖的方式
- 同步方法由static修飾,所以在main方法中可以使用多個目標
//main方法中
Thread thread1 = new Thread(new SingleThread3(), "淘票票");
Thread thread2 = new Thread(new SingleThread3(), "貓眼");
Thread thread3 = new Thread(new SingleThread3(), "美圖");
thread1.start();
thread2.start();
thread3.start();
- 同步方法是非靜態成員方法時,這個時候只能使用單目標
// main方法中
SingleThread2 singleThread2 = new SingleThread2();
Thread thread1 = new Thread(singleThread2, "淘票票");
Thread thread2 = new Thread(singleThread2, "貓眼");
Thread thread3 = new Thread(singleThread2, "美圖");
thread1.start();
thread2.start();
thread3.start();
- Lock 鎖
private static int ticket = 100;
//定義一個成員變量
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//在 a 的位置添加
lock.lock();
/*
* ab之間的代碼
*/
lock.unlock();
}
}