CountDownLatch與thread.join()的區(qū)別

今天學(xué)習(xí)CountDownLatch這個類,作用感覺和join很像,然后就百度了一下,看了他們之間的區(qū)別。所以在此記錄一下。

首先來看一下join,在當(dāng)前線程中,如果調(diào)用某個thread的join方法,那么當(dāng)前線程就會被阻塞,直到thread線程執(zhí)行完畢,當(dāng)前線程才能繼續(xù)執(zhí)行。join的原理是,不斷的檢查thread是否存活,如果存活,那么讓當(dāng)前線程一直wait,直到thread線程終止,線程的this.notifyAll 就會被調(diào)用。

我們來看一下這個應(yīng)用場景:假設(shè)現(xiàn)在公司有三個員工A,B,C,他們要開會。但是A需要等B,C準(zhǔn)備好之后再才能開始,B,C需要同時準(zhǔn)備。我們先用join模擬上面的場景。

Employee.java:

public class Employee extends Thread{
        
    private String employeeName;
    
    private long time;

    public Employee(String employeeName,long time){
        this.employeeName = employeeName;
        this.time = time;
    }
    
    @Override
    public void run() {
        try {
            System.out.println(employeeName+ "開始準(zhǔn)備");
            Thread.sleep(time);
            System.out.println(employeeName+" 準(zhǔn)備完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

JoinTest.java:

public class JoinTest {

    public static void main(String[] args) throws InterruptedException {
        Employee a = new Employee("A", 3000);
        Employee b = new Employee("B", 3000);
        Employee c = new Employee("C", 4000);
        
        b.start();
        c.start();
        
        b.join();
        c.join();
        System.out.println("B,C準(zhǔn)備完成");
        a.start();
    }
}

最后輸出結(jié)果如下:

C開始準(zhǔn)備
B開始準(zhǔn)備
B 準(zhǔn)備完成
C 準(zhǔn)備完成
B,C準(zhǔn)備完成
A開始準(zhǔn)備
A 準(zhǔn)備完成

可以看到,A總是在B,C準(zhǔn)備完成之后才開始執(zhí)行的。

CountDownLatch中我們主要用到兩個方法一個是await()方法,調(diào)用這個方法的線程會被阻塞,另外一個是countDown()方法,調(diào)用這個方法會使計數(shù)器減一,當(dāng)計數(shù)器的值為0時,因調(diào)用await()方法被阻塞的線程會被喚醒,繼續(xù)執(zhí)行。

接下來,我們用CountDownLatch來模擬一下。

Employee.java:

public class Employee extends Thread{

    private String employeeName;
    
    private long time;
    
    private CountDownLatch countDownLatch;

    public Employee(String employeeName,long time, CountDownLatch countDownLatch){
        this.employeeName = employeeName;
        this.time = time;
        this.countDownLatch = countDownLatch;
    }
    
    @Override
    public void run() {
        try {
            System.out.println(employeeName+ "開始準(zhǔn)備");
            Thread.sleep(time);
            System.out.println(employeeName+" 準(zhǔn)備完成");
            countDownLatch.countDown();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

CountDownLatchTest.java:

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        Employee a = new Employee("A", 3000,countDownLatch);
        Employee b = new Employee("B", 3000,countDownLatch);
        Employee c = new Employee("C", 4000,countDownLatch);
        
        b.start();
        c.start();
        countDownLatch.await();
        System.out.println("B,C準(zhǔn)備完成");
        a.start();
    }
}

輸出結(jié)果如下:

B開始準(zhǔn)備
C開始準(zhǔn)備
B 準(zhǔn)備完成
C 準(zhǔn)備完成
B,C準(zhǔn)備完成
A開始準(zhǔn)備
A 準(zhǔn)備完成

上面可以看到,CountDownLatch與join都能夠模擬上述的場景,那么他們有什么不同呢?這時候我們試想另外一個場景就能看到他們的區(qū)別了。

假設(shè)A,B,C的工作都分為兩個階段,A只需要等待B,C各自完成他們工作的第一個階段就可以執(zhí)行了。

我們來修改一下Employee類:

public class Employee extends Thread{

    private String employeeName;
    
    private long time;
    
    private CountDownLatch countDownLatch;

    public Employee(String employeeName,long time, CountDownLatch countDownLatch){
        this.employeeName = employeeName;
        this.time = time;
        this.countDownLatch = countDownLatch;
    }
    
    @Override
    public void run() {
        try {
            System.out.println(employeeName+ " 第一階段開始準(zhǔn)備");
            Thread.sleep(time);
            System.out.println(employeeName+" 第一階段準(zhǔn)備完成");
            
            countDownLatch.countDown();
            
            System.out.println(employeeName+ " 第二階段開始準(zhǔn)備");
            Thread.sleep(time);
            System.out.println(employeeName+" 第二階段準(zhǔn)備完成");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

CountDownLatchTest類不需要做修改,輸出結(jié)果入下:

B 第一階段開始準(zhǔn)備
C 第一階段開始準(zhǔn)備
B 第一階段準(zhǔn)備完成
B 第二階段開始準(zhǔn)備
C 第一階段準(zhǔn)備完成
C 第二階段開始準(zhǔn)備
B,C第一階段準(zhǔn)備完成
A 第一階段開始準(zhǔn)備
B 第二階段準(zhǔn)備完成
A 第一階段準(zhǔn)備完成
A 第二階段開始準(zhǔn)備
C 第二階段準(zhǔn)備完成
A 第二階段準(zhǔn)備完成

從結(jié)果可以看出,A在B,C第一階段準(zhǔn)備完成的時候就開始執(zhí)行了,不需要等到第二階段準(zhǔn)備完成。這種場景下,用join是沒法實(shí)現(xiàn)的。

總結(jié):調(diào)用join方法需要等待thread執(zhí)行完畢才能繼續(xù)向下執(zhí)行,而CountDownLatch只需要檢查計數(shù)器的值為零就可以繼續(xù)向下執(zhí)行,相比之下,CountDownLatch更加靈活一些,可以實(shí)現(xiàn)一些更加復(fù)雜的業(yè)務(wù)場景。

個人博客:https://www.zhaojun.ink

參考:https://blog.csdn.net/zhutulang/article/details/48504487

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容