多線程CountDownLatch和Join

如果現在有五個線程A、B、C、D、E,請問如何用E線程用於統計A、B、C、D四個線程的結果?

題意需要用E線程統計A、B、C、D四個線程,也就是說E線程必須要等到前面四個線程運行結束之後才能執行。那麼如何使用E線程來統計前面四個線程的結果呢?

下面介紹兩種實現方法:

一、CountDownLatch

CountDownLatch是一種java.util.concurrent包下一個同步工具類,它允許一個或多個線程等待直到在其他線程中一組操作執行完成。

我們可以將CountDownLatch看作一個計數器,可以給定其一個數來對其進行初始化。當它計數的值變爲0時,纔可以執行後續的步驟。

1
public CountDownLatch(int count)

CountDownLatch有兩個方法是我們常用的:await();和countDown();

await()函數用於阻塞當前線程直到CountDownLatch的計數值變爲0;

countDown()方法用於將當前CountDownLatch的計數值減1;

簡單的介紹了CountDownLatch的作用和用法之後,我們看下如下的代碼:

複製代碼
import java.util.concurrent.CountDownLatch;
public class  Test1{
    public static void main(String[] args) throws InterruptedException {
        int number = 3;
        CountDownLatch latch =  new CountDownLatch(number);
        
        for(int i=0;i<3;i++){
            ThreadDemo demo = new ThreadDemo(latch);
            demo.start();
            System.out.println(i);
        }
        latch.await();
        System.out.println("Check it Out");
    }
}

class ThreadDemo extends Thread{
    
    private CountDownLatch latch;
    
    public ThreadDemo(CountDownLatch latch){
        this.latch = latch;
    }
    
    public void run(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        latch.countDown();
    }
}
複製代碼

我們首先創建了一個CountDownLatch對象給定一個number將其初始化,需要注意的是當前CountDownLatch對象的值減爲0之後,該對象便失去了作用。

同時我們提供了繼承自Thread的ThreadDemo類,它包含了一個CountDownLatch對象。當我們創建ThreadDemo對象時,會將CountDowmLatch對象注入其中。

在TreadDemo類的run()方法中,我們執行了兩步動作:延遲5秒後將CountDownLatch的計數值減1。

在main函數中,我們利用for循環創建了三個ThreadDemo對象並執行他們的run()方法。添加和不添加latch.await()語句將會得到兩種執行結果。

1、添加latch.await()語句

  執行結果:

  0

  1

  2

  Check it Out

  我們會發現0 1 2幾乎是同時打印出來的,但是“Check it Out”大概等待了5秒左右的時間後纔打印,這說明了其實“Check it Out”是等待前面三個線程執行完countDown()方法之後將latch的值減爲0之後才執行的。

2、無latch.await()語句

  執行結果:

  0

  1

  2

  Check it Out

  觀察運行結果我們會發現,0 1 2和“Check it Out”幾乎是同時出現的,也就是說“Check it Out”並沒有等待前面三個線程執行完成之後才執行。

 

  CountDowLlatch的用途即是讓一組線程先執行,知道countdownlatch對象的計數值到0後,讓後續的線程繼續執行。

二、join方法實現

   事實上,join方法也可以實現同樣的效果!代碼如下:

複製代碼
import java.util.concurrent.CountDownLatch;
public class  Test{
    public static void main(String[] args) throws InterruptedException {
        int number = 3;
        CountDownLatch latch =  new CountDownLatch(number);
        ThreadDemo thread1 = new ThreadDemo(1);
        ThreadDemo thread2 = new ThreadDemo(2);
        thread1.start();
        thread1.join();
        System.out.println("----");
        thread2.start(); 
        thread2.join();
        System.out.println("main is end!");
        
        
    }
}

class ThreadDemo extends Thread{
    private int number;
    public ThreadDemo(int number){
        this.number = number;
    }
    public void run(){
        System.out.println("Thread"+number+" is running");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread"+number+"is end");
    }
}
複製代碼

運行結果如下:

Thread1 is running

Thread1is end

----

Thread2 is running

Thread2is end

main is end!

可以看到thread1阻塞了thread2,只有當thread1和thread2均執行結束後,main方法才能繼續執行。如果想要thread1和thread2同時執行的話,只需要做如下簡單的變動。

thread1.start();
thread1.join();
thread2.start(); 
thread2.join();
System.out.println("main is end!");

運行結果如下:

Thread1 is running

Thread2 is running

Thread1is end

Thread2is end

main is end!

因此,如果我們需要某些線程等待指定任務執行完畢之後執行,選擇join方法也是一種選擇;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章