標籤:
該文章轉自:http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html
CountDownLatch
1、類介紹
一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。用給定的計數 初始化 CountDownLatch。由於調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之後,會釋放所有等待的線程,await 的所有後續調用都將立即返回。這種現象只出現一次——計數無法被重設。 一個線程(或者多個), 等待另外N個線程完成某個事情之後才能執行
2、使用情境
在一些應用場合中,需要等待某個條件達到要求後才能做後面的事情;同時當線程都完成後也會觸發事件,以便進行後面的操作。 這個時候就可以使用CountDownLatch。CountDownLatch最重要的方法是countDown()和await(),前者主要是倒數一次,後者是等待倒數到0,如果沒有到達0,就只有阻塞等待了。3、方法說明countDown
public void countDown()
-
遞減鎖存器的計數,如果計數到達零,則釋放所有等待的線程。如果當前計數大於零,則將計數減少。如果新的計數為零,出於線程調度目的,將重新啟用所有的等待線程。
如果當前計數等於零,則不發生任何操作。
await
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
-
使當前線程在鎖存器倒計數至零之前一直等待,除非線程被中斷或超出了指定的等待時間。如果當前計數為零,則此方法立刻返回
true 值。
如果當前計數大於零,則出於線程調度目的,將禁用當前線程,且在發生以下三種情況之一前,該線程將一直處於休眠狀態:
- 由於調用
countDown() 方法,計數到達零;或者
- 其他某個線程中斷當前線程;或者
- 已超出指定的等待時間。
如果計數到達零,則該方法返回 true 值。
如果當前線程:
- 在進入此方法時已經設定了該線程的中斷狀態;或者
- 在等待時被中斷,
則拋出 InterruptedException,並且清除當前線程的已中止狀態。如果超出了指定的等待時間,則傳回值為 false。如果該時間小於等於零,則此方法根本不會等待。
-
-
參數:
-
timeout - 要等待的最長時間
-
unit -
timeout 參數的時間單位。
-
返回:
-
如果計數到達零,則返回
true;如果在計數到達零之前超過了等待時間,則返回
false
-
拋出:
-
InterruptedException - 如果當前線程在等待時被中斷
4、相關執行個體
1 public class CountDownLatchTest { 2 3 // 類比了100米賽跑,10名選手已經準備就緒,只等裁判一聲令下。當所有人都到達終點時,比賽結束。 4 public static void main(String[] args) throws InterruptedException { 5 6 // 開始的倒數鎖 7 final CountDownLatch begin = new CountDownLatch(1); 8 9 // 結束的倒數鎖 10 final CountDownLatch end = new CountDownLatch(10); 11 12 // 十名選手 13 final ExecutorService exec = Executors.newFixedThreadPool(10); 14 15 for (int index = 0; index < 10; index++) {16 final int NO = index + 1; 17 Runnable run = new Runnable() {18 public void run() { 19 try { 20 // 如果當前計數為零,則此方法立即返回。21 // 等待22 begin.await(); 23 Thread.sleep((long) (Math.random() * 10000)); 24 System.out.println("No." + NO + " arrived"); 25 } catch (InterruptedException e) { 26 } finally { 27 // 每個選手到達終點時,end就減一28 end.countDown();29 } 30 } 31 }; 32 exec.submit(run);33 } 34 System.out.println("Game Start"); 35 // begin減一,開始遊戲36 begin.countDown(); 37 // 等待end變為0,即所有選手到達終點38 end.await(); 39 System.out.println("Game Over"); 40 exec.shutdown(); 41 }42 }
5、輸出結果
Game Start
No.9 arrived
No.6 arrived
No.8 arrived
No.7 arrived
No.10 arrived
No.1 arrived
No.5 arrived
No.4 arrived
No.2 arrived
No.3 arrived
Game Over 資料補充,下面的例子來源於thinking in java(跟上面的例子不同之處在於上面的例子是一個任務等到多個任務執行完成,而thinking in java的就進階一些了,是多個任務等到多個任務執行完成解鎖): 代碼1:
1 package com.cakushin.thread.countdownlatch; 2 3 import java.util.Random; 4 import java.util.concurrent.CountDownLatch; 5 6 public class TaskPortion implements Runnable { 7 private static int counter = 0; 8 private final int id = counter++; 9 private static Random rand = new Random(47);10 private final CountDownLatch latch;11 12 public TaskPortion(CountDownLatch latch){13 this.latch = latch;14 }15 16 @Override17 public void run() {18 try {19 doWork();20 latch.countDown();21 } catch (InterruptedException e) {22 e.printStackTrace();23 }24 }25 26 private void doWork() throws InterruptedException {27 Thread.sleep(rand.nextInt(2000));28 System.out.println(this + " completed!");29 }30 31 public String toString(){32 return String.format("%1$-3d", id);33 }34 35 }
代碼2:
1 package com.cakushin.thread.countdownlatch; 2 3 import java.util.concurrent.CountDownLatch; 4 5 public class WaitingTask implements Runnable { 6 private static int counter = 0; 7 private final int id = counter++; 8 private final CountDownLatch latch; 9 10 public WaitingTask(CountDownLatch latch){11 this.latch = latch;12 }13 14 @Override15 public void run() {16 try {17 latch.await();18 System.out.println("Latch barrier passed for " + this);19 } catch (InterruptedException e) {20 System.out.println(this + " interrupted");21 }22 }23 24 public String toString(){25 return String.format("WatingTask %1$-3d", id);26 }27 28 }
代碼3:
1 package com.cakushin.thread.countdownlatch; 2 3 import java.util.concurrent.CountDownLatch; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.Executors; 6 7 public final class CountDownLatchDemo { 8 9 static final int SIZE = 100;10 11 /**12 * @author Administrator13 * @param args14 */15 public static void main(String[] args) {16 ExecutorService exec = Executors.newCachedThreadPool();17 CountDownLatch latch = new CountDownLatch(SIZE);18 for(int i = 0; i < 10; i++){19 exec.execute(new WaitingTask(latch));20 }21 for(int i = 0; i < 100; i++){22 exec.execute(new TaskPortion(latch));23 }24 System.out.println("Launched all tasks");25 exec.shutdown();26 }27 28 }
JAVA並發,CountDownLatch使用