漫畫:Java併發閉鎖CountDownLatch

(以前掘金的「程序員七貓」帳號找不到了,只好從新開了個,會把前2篇文章都搬家到這裏到)程序員


本次漫畫改編自鴻洋的《Java 併發專題 :閉鎖 CountDownLatch 之一家人一塊兒吃個飯》 https://blog.csdn.net/lmj623565791/article/details/26626391bash

謝謝鴻洋大神的支持!網絡

某天,小貓咪一家決定要去飯館吃飯,到了快下班的時候,family·f3羣裏開始聊起天來併發

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的使用場景

一、例如上例中全部人都到達飯店而後吃飯

二、某個操做須要的資源初始化完畢

三、某個服務依賴的線程所有開啓等等...

上烤魚嘍~

烤魚圖源來自網絡侵權則刪

依然感謝支持個人小夥伴們以及網友們~

您的關注與支持是我最大的動力~

本人公衆號:程序員七貓

歡迎關注點贊以及提建議

相關文章
相關標籤/搜索