Java並發和多線程4:使用通用同步工具CountDownLatch實現線程等待

來源:互聯網
上載者:User

Java並發和多線程4:使用通用同步工具CountDownLatch實現線程等待
CountDownLatch,一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。


用給定的計數 初始化 CountDownLatch。由於調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。
之後,會釋放所有等待的線程,await 的所有後續調用都將立即返回。
這種現象只出現一次——計數無法被重設。如果需要重設計數,請考慮使用 CyclicBarrier。


CountDownLatch 是一個通用同步工具,它有很多用途。
將計數 1 初始化的 CountDownLatch 用作一個簡單的開/關鎖存器,或入口:在通過調用 countDown() 的線程開啟入口前,所有調用 await的線程都一直在入口處等待。
用 N 初始化的 CountDownLatch 可以使一個線程在 N 個線程完成某項操作之前一直等待,或者使其在某項操作完成 N 次之前一直等待。


CountDownLatch 的一個有用特性是,它不要求調用 countDown 方法的線程等到計數到達零時才繼續,而在所有線程都能通過之前,它只是阻止任何線程繼續通過一個 await。




用法1: 下面給出了兩個類,其中一組 worker 線程使用了兩個倒計數鎖存器:
// 第一個類是一個啟動訊號,在 driver 為繼續執行 worker 做好準備之前,它會阻止所有的 worker 繼續執行。
// 第二個類是一個完成訊號,它允許 driver 在完成所有 worker 之前一直等待。

class Driver {void start() throws InterruptedException {CountDownLatch startSignal = new CountDownLatch(1);int N = 5;CountDownLatch doneSignal = new CountDownLatch(N);for (int i = 0; i < N; i++) {Worker worker = new Worker(startSignal, doneSignal,i);Thread thread = new Thread(worker);thread.start();}doSomethingElse(1); // 所有線程都還沒有開始執行startSignal.countDown(); // 讓所有線程開始執行doSomethingElse(2);doneSignal.await(); // 等待所有線程結束doSomethingElse(3);}// 執行一些其它的事情,具體結合實際情況private void doSomethingElse(int i) {System.out.println("doSomethingElse-"+i);}}class Worker implements Runnable {private final CountDownLatch startSignal;private final CountDownLatch doneSignal;private final int i;Worker(CountDownLatch startSignal, CountDownLatch doneSignal,int i) {this.startSignal = startSignal;this.doneSignal = doneSignal;this.i=i;}public void run() {try {startSignal.await();doWork(i);doneSignal.countDown();} catch (InterruptedException ex) {ex.printStackTrace();}}void doWork(int i) {System.out.println("doWork-"+i);}}






// 另一種典型用法2,將一個問題分成 N 個部分,用執行每個部分並讓鎖存器倒計數的 Runnable 來描述每個部分,然後將所有 Runnable
// 加入到 Executor 隊列。當所有的子部分完成後,協調線程就能夠通過
// await。(當線程必須用這種方法反覆倒計數時,可改為使用CyclicBarrier。)


class Driver2 {void start() throws InterruptedException {int N = 5;CountDownLatch doneSignal = new CountDownLatch(N);ExecutorService e = Executors.newFixedThreadPool(3);// 建立並執行線程for (int i = 0; i < N; ++i) {WorkerRunnable workerRunnable = new WorkerRunnable(doneSignal, i);e.execute(workerRunnable);}// 等待所有線程結束doneSignal.await();//手動關閉,才會停止所有線程e.shutdown();}}class WorkerRunnable implements Runnable {private final CountDownLatch doneSignal;private final int i;WorkerRunnable(CountDownLatch doneSignal, int i) {this.doneSignal = doneSignal;this.i = i;}public void run() {doWork(i);doneSignal.countDown();}void doWork(int i) {System.out.println("doWork-" + i);}}




運行程式
package cn.fansunion.executorframework;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//Driver中的若干Thread,執行完畢後,自動就關閉了Driver driver = new Driver();driver.start();//Driver2中,需要手動調用ExecutorService.shutdown關閉線程Driver2 driver2 = new Driver2();driver2.start();}}



控制台結果
doSomethingElse-1
doSomethingElse-2
doWork-0
doWork-2
doWork-4
doWork-3
doWork-1
doSomethingElse-3
doWork-1
doWork-0
doWork-3
doWork-4
doWork-2

更多程式碼範例:
http://git.oschina.net/fansunion/Concurrent(逐步更新中)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.