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 之前一直等待。
// 另一種典型用法2,將一個問題分成 N 個部分,用執行每個部分並讓鎖存器倒計數的 Runnable 來描述每個部分,然後將所有 Runnable
// 加入到 Executor 佇列。當所有的子部分完成後,協調執行緒就能夠通過
// await。(當執行緒必須用這種方法反覆倒計數時,可改為使用CyclicBarrier。)
執行程式
控制檯結果
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(逐步更新中)
參考資料:
有條件地終止 ScheduledExecutorService 中執行的定時任務
http://www.oschina.net/question/1158769_119659?sort=time
JDK API 文件
用給定的計數 初始化 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(逐步更新中)
參考資料:
有條件地終止 ScheduledExecutorService 中執行的定時任務
http://www.oschina.net/question/1158769_119659?sort=time
JDK API 文件
相關文章
- 併發工具類(一)等待多執行緒的CountDownLatch執行緒CountDownLatch
- Java:多執行緒等待所有執行緒結束(CountDownLatch/CyclicBarrier) .Java執行緒CountDownLatch
- Java多執行緒同步工具類之CountDownLatchJava執行緒CountDownLatch
- java多執行緒10:併發工具類CountDownLatch、CyclicBarrier和SemaphoreJava執行緒CountDownLatch
- 多執行緒與併發----CycliBarrier、CountDownLatch 和 Exchanger同步執行緒CountDownLatch
- java 多執行緒CountDownLatchJava執行緒CountDownLatch
- Java多執行緒/併發07、Thread.Join()讓呼叫執行緒等待子執行緒Java執行緒thread
- 多執行緒和多執行緒同步執行緒
- java多執行緒系列:CountDownLatchJava執行緒CountDownLatch
- java 多執行緒 CountDownLatch用法Java執行緒CountDownLatch
- Java 併發和多執行緒(一) Java併發性和多執行緒介紹[轉]Java執行緒
- 【java 多執行緒】多執行緒併發同步問題及解決方法Java執行緒
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- Java多執行緒/併發11、執行緒同步通訊:notify、waitJava執行緒AI
- [Java併發]執行緒的並行等待Java執行緒並行
- JAVA多執行緒併發Java執行緒
- java多執行緒詳解(併發,並行,同步)Java執行緒並行
- Java併發和多執行緒:序Java執行緒
- java多執行緒與併發 - 併發工具類Java執行緒
- 4、Linux多執行緒,執行緒同步(2)Linux執行緒
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- Java多執行緒/併發08、中斷執行緒 interrupt()Java執行緒
- JAVA多執行緒詳解(3)執行緒同步和鎖Java執行緒
- 多執行緒與併發----Semaphere同步執行緒
- java 多執行緒 –同步Java執行緒
- java 多執行緒 --同步Java執行緒
- Java 併發:執行緒、執行緒池和執行器全面教程Java執行緒
- java 多執行緒 併發 面試Java執行緒面試
- CountDownLatch 多執行緒同步輔助類用法CountDownLatch執行緒
- JAVA多執行緒和併發基礎Java執行緒
- 啃碎併發(六):Java執行緒同步與實現Java執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- 用多執行緒,實現併發,TCP執行緒TCP
- Java併發實戰一:執行緒與執行緒安全Java執行緒
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- Java多執行緒——執行緒Java執行緒
- Java多執行緒/併發12、多執行緒訪問static變數Java執行緒變數
- #大學#Java多執行緒學習02(執行緒同步)Java執行緒