1. 程式人生 > >多執行緒中CountDownLatch的含義以及和join的區別

多執行緒中CountDownLatch的含義以及和join的區別

任何執行緒,通常是應用程式的主執行緒,呼叫CountDownLatch.await()將等到計數達到零或被另一個執行緒中斷。所有其他執行緒都需要CountDownLatch.countDown()在完成或準備好後通過呼叫來倒計時。

一旦計數達到零,等待執行緒就會繼續。其中一個缺點/優點CountDownLatch是它不可重複使用:一旦計數達到零,就不能再使用CountDownLatch了。

使用CountDownLatch當一個執行緒(比如主執行緒),需要等待一個或多個執行緒來完成,才能繼續處理。

CountDownLatchJava 中使用的典型示例是伺服器端核心Java應用程式,它使用服務體系結構,其中多個服務由多個執行緒提供,並且應用程式無法在所有服務成功啟動之前開始處理。

package CountDownLatch_6;

import java.util.concurrent.CountDownLatch;

public class Manager {
	public static void main(String[] args) throws InterruptedException {
		CountDownLatch latch=new CountDownLatch(2);
		MyDevTeam devTeam=new MyDevTeam(latch, "dev1");
		MyDevTeam devTeam2=new MyDevTeam(latch, "dev2");
		devTeam.start();
		devTeam2.start();
		latch.await();
		MyQATeam qa=new MyQATeam();
		qa.start();
	}
	
}
class MyDevTeam extends Thread{
	CountDownLatch latch;
	public MyDevTeam(CountDownLatch latch,String name ) {
		// TODO Auto-generated constructor stub
		super(name);
		this.latch=latch;
	}
	
	public void run(){
		System.out.println("任務分配給"+currentThread().getName());
		try {
			Thread.sleep(2000);
			System.out.println(currentThread().getName()+"開始執行");
			latch.countDown();
			
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("任務已經被"+currentThread().getName()+"執行完畢");
		
	}
}

class MyQATeam extends Thread{
	public void run(){
		System.out.println("任務分配給qa執行");

		
		System.out.println("qa完成該任務");
	}
}

執行結果:

任務分配給dev2 任務分配給dev1 dev2開始執行 任務已經被dev2執行完畢 dev1開始執行 任務已經被dev1執行完畢 任務分配給qa執行 qa完成該任務

JOIN的限制: 以上示例也可以通過JOIN實現,但JOIN不能在兩種情況下使用:

  1. 當我們使用ExecutorService而不是Thread類來建立執行緒時。
  2. 修改以上示例,管理員希望在開發完成80%任務後立即將程式碼切換到QA團隊。這意味著CountDownLatch允許我們修改可用於等待另一個執行緒進行部分執行的實現。

上述程式碼修改

public void run(){
		System.out.println("任務分配給"+currentThread().getName());
		try {
			Thread.sleep(2000);
			System.out.println(currentThread().getName()+"第一階段任務完成");
			latch.countDown();
			Thread.sleep(2000);
			System.out.println(currentThread().getName()+"第二階段任務完成");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("任務已經被"+currentThread().getName()+"執行完畢");
		
	}
}

執行結果:

任務分配給dev1 任務分配給dev2 dev2第一階段任務完成 dev1第一階段任務完成 任務分配給qa執行 qa完成該任務 dev1第二階段任務完成 任務已經被dev1執行完畢 dev2第二階段任務完成 任務已經被dev2執行完畢  

由執行結果可知qa在第二階段任務執行之前就已經執行,

這種場景下,用join是沒法實現的。

總結:呼叫join方法需要等待thread執行完畢才能繼續向下執行,而CountDownLatch只需要檢查計數器的值為零就可以繼續向下執行,相比之下,CountDownLatch更加靈活一些,可以實現一些更加複雜的業務場景。