Lock實現線程間定製化通信 案例 要求 三個線程,AA BB CC AA線程列印5次,BB線程列印10次,CC線程列印15次 代碼實現 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lo ...
Lock實現線程間定製化通信
案例
要求
三個線程,AA BB CC AA線程列印5次,BB線程列印10次,CC線程列印15次
代碼實現
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author 長名06
* @version 1.0
* 線程定製化通信
*/
//第一步,創建共用資源,和操作方法
class ShareFlag {
private Lock lock = new ReentrantLock();
private int flag = 1;
private Condition c1 = lock.newCondition();//一個Condition對象,只能喚醒由該對象阻塞的線程
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5(int loop) throws InterruptedException {
lock.lock();
try {
//第四步,避免虛假喚醒現象
while (flag != 1) {//第2.1步 判斷是否滿足線程工作條件,阻塞
c1.await();
}
//第2.2步 具體執行
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i +"次輸出"
+ "flag=" + flag + "輪數" + loop);
}
flag = 2;
//通知(喚醒等待線程)
c2.signal();
} finally {
lock.unlock();
}
}
public void print10(int loop) throws InterruptedException {
lock.lock();
try {
while (flag != 2) {
c2.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i +"次輸出"
+ "flag=" + flag + "輪數" + loop);
}
flag = 3;
//通知(喚醒等待線程)
c3.signal();
} finally {
lock.unlock();
}
}
public void print15(int loop) throws InterruptedException {
lock.lock();
try {
while (flag != 3) {
c3.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i +"次輸出"
+ "flag=" + flag + "輪數" + loop);
}
flag = 1;
//通知(喚醒等待線程)
c1.signal();
} finally {
lock.unlock();
}
}
}
public class ThreadDemoByCust {
public static void main(String[] args) {
ShareFlag shareFlag = new ShareFlag();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
shareFlag.print5(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "AA").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
shareFlag.print10(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "BB").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
shareFlag.print15(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "CC").start();
}
}
學習時,關於代碼的疑問
不理解,為什麼一定是,AA線程執行完後,,BB線程執行完後,是c3是c2去執行喚醒一個等待線程操作去執行喚醒一個等待線程的操作,CC線程執行完後,是c1執行喚醒一個等待線程的操作。先往後面看,後續回來解答這個問題。
解答
是為了滿足要求中的順序,最開始三個AA,BB,CC線程,並行執行,因為flag初始值是1,所以AA先執行第一次迴圈,執行print5,然後迴圈輸出5次後,flag = 2了(AA被c1阻塞),為了保證要求,再BB輸出10次,則需要使用c2去喚醒BB線程,為什麼是c2,因為BB線程在,最開始flag = 1時,是由c2去阻塞的,這裡如果是c3對象阻塞的,則必須要用c3對象喚醒,因為Condition對象,只能喚醒由該對象阻塞的線程。後面BB線程切換CC線程,CC線程切換AA線程也是同理。
只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。