(以前掘金的「程序員七貓」帳號找不到了,只好從新開了個,會把前2篇文章都搬家到這裏到)程序員
本次漫畫改編自鴻洋的《Java 併發專題 :閉鎖 CountDownLatch 之一家人一塊兒吃個飯》 https://blog.csdn.net/lmj623565791/article/details/26626391bash
謝謝鴻洋大神的支持!網絡
某天,小貓咪一家決定要去飯館吃飯,到了快下班的時候,family·f3羣裏開始聊起天來併發
如下是來自這位可憐的貓咪爸爸的吐槽spa
下班到了(歡呼!),你們都開始出發去飯店了.net
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小時,那還吃什麼飯,直接買份夜宵算了!code
貓咪爸爸、媽媽、小貓咪都是各自按下班時間出發的,屬於併發的,因此咱們換個場景 orm
開啓爸爸走路、媽媽坐公交、小貓咪坐地鐵三個線程,以下cdn
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的使用場景
一、例如上例中全部人都到達飯店而後吃飯
二、某個操做須要的資源初始化完畢
三、某個服務依賴的線程所有開啓等等...
上烤魚嘍~
依然感謝支持個人小夥伴們以及網友們~
您的關注與支持是我最大的動力~
本人公衆號:程序員七貓
歡迎關注點贊以及提建議