線程間通信 多線程編程步驟(中) 第一,創建資源類,創建屬性和操作方法;第二,在資源操作方法,1)判斷 2)工作 3)通知;第三,創建多線程調用資源類的方法。 案例 要求,有兩個線程,實現對一個初始值為0的變數,一個線程對值+1,一個線程對值-1。 代碼實現 /** * @author 長名06 * ...
線程間通信
多線程編程步驟(中)
第一,創建資源類,創建屬性和操作方法;第二,在資源操作方法,1)判斷 2)工作 3)通知;第三,創建多線程調用資源類的方法。
案例
要求,有兩個線程,實現對一個初始值為0的變數,一個線程對值+1,一個線程對值-1。
代碼實現
/**
* @author 長名06
* @version 1.0
* 線程通信案例 兩個線程對一個值進行 decr incr
* 用synchronized關鍵字實現
*/
class Share {
private int number;
public synchronized void incr() throws InterruptedException {
/**
* 這樣寫,會出現虛假喚醒問題,因為如果當前線程被等待,然後被喚醒時,if語句,就不會再次進行判斷
* 有可能出現,此時的number != 0 當時依舊進行了 +1操作 減方法類似
* wait()方法再api文檔中,就提醒,在一個參數版本中,中斷和虛假喚醒是可能的,並且該方法應該始終在迴圈中使用:
* 線程在哪裡被阻塞就會在哪裡,被喚醒,也就是說線程被阻塞時,是滿足number!= 0,所以阻塞,但是因為一個線程執行完後,釋
* 放鎖,然後喚醒等待的線程,是隨機喚醒的,有可能當前+1的條件依舊不滿足,但是系統卻喚醒了該線程,因為是if語句,在
* this.wait()處被喚醒,程式繼續執行,導致其實條件不滿足,卻執行了+1操作,所以使用while()迴圈進行判斷,只能當條件滿
* 足且線程被喚醒才執行incr方法
* if (number != 0){//條件
* this.wait();
* }
*/
while (number != 0) {
this.wait();
}
//加1
number++;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知其他線程
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
while (number != 1) {
this.wait();
}
//減1
number--;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知其他線程
this.notifyAll();
}
}
public class ThreadDemo {
public static void main(String[] args) {
Share share = new Share();
new Thread(() -> {
for (int i = 0; i < 25; i++) {
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "aa").start();
new Thread(() -> {
for (int i = 0; i < 25; i++) {
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "bb").start();
}
}
多線程編程步驟(下)
第一,創建資源類,創建屬性和操作方法;第二,在資源操作方法,1) 判斷 2)工作 3)通知;第三,創建多線程調用資源類的方法;第四,防止虛假喚醒問題。
Lock實現上述案例
代碼
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 長名06
* @version 1.0
*/
//第一步創建資源類,屬性和操作方法
class ShareByLock {
private int number;
//獲得鎖
private final ReentrantLock lock = new ReentrantLock();
//為當前鎖,創建一個新的condition,並綁定到該鎖上
private Condition condition = lock.newCondition();
public void incr() throws InterruptedException {
//上鎖
lock.lock();
//第二步 進行
// 1.判斷(線程切換的條件)
// 2.執行(線程執行的具體操作)
// 3.通知(喚醒等待的其他線程)
try {
//判斷
//第四步 防止虛假喚醒現象
while (number != 0) {
condition.await();
}
//執行
number++;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知
condition.signalAll();
} finally {
//解鎖
lock.unlock();
}
}
public void decr() throws InterruptedException {
//上鎖
lock.lock();
try {
//判斷
while (number != 1) {
condition.await();
}
//執行
number--;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知
condition.signalAll();
} finally {
//解鎖
lock.unlock();
}
}
}
public class ThreadDemoByLock {
public static void main(String[] args) {
ShareByLock shareByLock = new ShareByLock();
//第三步 創建多個線程調用資源類的方法
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareByLock.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "aa").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareByLock.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "bb").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareByLock.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "cc").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
shareByLock.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "dd").start();
}
}
只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。