(之前掘金的“程式設計師七貓”賬號找不到了,只好重新開了個,會把前2篇文章都搬家到這裡到)
本次漫畫改編自鴻洋的《Java 併發專題 :閉鎖 CountDownLatch 之一家人一起吃個飯》
https://blog.csdn.net/lmj623565791/article/details/26626391
謝謝鴻洋大神的支援!
某天,小貓咪一家決定要去飯館吃飯,到了快下班的時候,family·f3群裡開始聊起天來
以下是來自這位可憐的貓咪爸爸的吐槽
下班到了(歡呼!),大家都開始出發去飯店了
public class Test1
{
/**
* 模擬爸爸去飯店
*/
public static void fatherToRes()
{
System.out.println("爸爸步行去飯店需要3小時。");
}
/**
* 模擬媽媽去飯店
*/
public static void motherToRes()
{
System.out.println("媽媽擠公交去飯店需要2小時。");
}
/**
* 模擬我去飯店
*/
public static void meToRes()
{
System.out.println("我乘地鐵去飯店需要1小時。");
}
/**
* 模擬一家人到齊了
*/
public static void togetherToEat()
{
System.out.println("一家人到齊了,開始吃飯");
}
public static void main(String[] args)
{
fatherToRes();
motherToRes();
meToRes();
togetherToEat();
}
}
複製程式碼
輸出結果
爸爸步行去飯店需要3小時。
媽媽擠公交去飯店需要2小時。
我乘地鐵去飯店需要1小時。
一家人到齊了,開始吃飯
複製程式碼
!停停停 !是不是哪裡不對了,為什麼是貓咪爸爸走完3小時,媽媽再去坐公交車2小時,然後才等到小貓咪乘地鐵1小時,這整整花了6小時,那還吃什麼飯,直接買份夜宵算了!
貓咪爸爸、媽媽、小貓咪都是各自按下班時間出發的,屬於併發的,所以我們換個場景
開啟爸爸走路、媽媽坐公交、小貓咪坐地鐵三個執行緒,如下
public static void main(String[] args)
{
new Thread()
{
public void run()
{
fatherToRes();
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
};
}.start();
new Thread()
{
public void run()
{
meToRes();
};
}.start();
togetherToEat();
}
複製程式碼
輸出結果
一家人到齊了,開始吃飯
我乘地鐵去飯店需要1小時。
媽媽擠公交去飯店需要2小時。
爸爸步行去飯店需要3小時。
複製程式碼
喵?喵?喵?!
開啟了執行緒併發了,但是貌似也不對啊,一家三都還沒到飯館,怎麼能先吃起飯來?
於是再換一個方法
private static volatile int i = 3;
public static void main(String[] args)
{
new Thread()
{
public void run()
{
fatherToRes();
i--;
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
i--;
};
}.start();
new Thread()
{
public void run()
{
meToRes();
i--;
};
}.start();
while (i != 0);
togetherToEat();
}
複製程式碼
關鍵修飾符volatile
volatile作用:當多個執行緒操作同一個變數時,用於保證變數修改對於其他執行緒的可見性。但是volatile不能保證原子性,而i–不是原子操作。所以建議正常使用同步塊或者AtomicLong.decrementAndGet()實現–。
馬上來~
private static CountDownLatch latch = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException
{
new Thread()
{
public void run()
{
fatherToRes();
latch.countDown();
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
latch.countDown();
};
}.start();
new Thread()
{
public void run()
{
meToRes();
latch.countDown();
};
}.start();
latch.await();
togetherToEat();
}
複製程式碼
輸出結果
我乘地鐵去飯店需要1小時。
媽媽擠公交去飯店需要2小時。
爸爸步行去飯店需要3小時。
一家人到齊了,開始吃飯
複製程式碼
CountDowmLatch是一種靈活的閉鎖實現,包含一個計數器,該計算器初始化為一個正數,表示需要等待事件的數量。countDown方法遞減計數器,表示有一個事件發生,而await方法等待計數器到達0,表示所有需要等待的事情都已經完成,那麼就可以繼續執行當前執行緒了。
CountDownLatch的使用場景
1、例如上例中所有人都到達飯店然後吃飯
2、某個操作需要的資源初始化完畢
3、某個服務依賴的執行緒全部開啟等等…
上烤魚嘍~
依然感謝支援我的小夥伴們以及網友們~
您的關注與支援是我最大的動力~
本人公眾號:程式設計師七貓
歡迎關注點贊以及提建議