Java并发编程札记-(四)JUC锁-08CountDownLatch
2017-12-17 20:18
411 查看
CountDownLatch是一个通用同步器,用于同步一个或多个任务。在完成一组正在其他线程中执行的任务之前,它允许一个或多个线程一直等待。
可以用一个初始计数值来初始化CountDownLatch对象,任何在这个对象上调用wait()的方法都将阻塞,直至计数值到达0。每完成一个任务,都可以在这个对象上调用countDown()减少计数值。当计数值减为0,所有等待的线程都会被释放。CountDownLatch的计数值不能重置。如果需要重置计数器,请考虑使用CyclicBarrier。
使用场景
作为一个通用同步工具,CountDownLatch有许多用途。比如,将计数值初始化为1的CountDownLatch用作一个简单的开/关:在通过调用countDown()的线程打开入口前,所有调用await()的线程都一直在入口处等待;用N初始化的 CountDownLatch可以使一个线程在N个线程完成某项操作之前一直等待,或者使其在某项操作完成N次之前一直等待。
例1:CountDownLatch作为开关
执行结果为:
Thread-2启动了
Thread-0启动了
Thread-1启动了
Thread-3启动了
Thread-4启动了
Thread-2工作了
Thread-3工作了
Thread-1工作了
Thread-4工作了
Thread-0工作了
down
从结果中看到,5个任务线程依次启动,但每一个都没有执行完,这是因为run方法中的
例2:CountDownLatch分割任务
源码
待补充
本文就讲到这里,想了解Java并发编程更多内容请参考:
Java并发编程札记-目录
可以用一个初始计数值来初始化CountDownLatch对象,任何在这个对象上调用wait()的方法都将阻塞,直至计数值到达0。每完成一个任务,都可以在这个对象上调用countDown()减少计数值。当计数值减为0,所有等待的线程都会被释放。CountDownLatch的计数值不能重置。如果需要重置计数器,请考虑使用CyclicBarrier。
使用场景
作为一个通用同步工具,CountDownLatch有许多用途。比如,将计数值初始化为1的CountDownLatch用作一个简单的开/关:在通过调用countDown()的线程打开入口前,所有调用await()的线程都一直在入口处等待;用N初始化的 CountDownLatch可以使一个线程在N个线程完成某项操作之前一直等待,或者使其在某项操作完成N次之前一直等待。
例1:CountDownLatch作为开关
public class Driver { public static void main(String args[]) throws InterruptedException { int n = 5; // 启动信号,在driver为继续执行worker做好准备之前,它会阻止所有的worker继续执行。 CountDownLatch startSignal = new CountDownLatch(1); // 完成信号,它允许driver在完成所有 worker之前一直等待。 CountDownLatch doneSignal = new CountDownLatch(n); for (int i = 0; i < n; ++i) // 创建并启动所有线程 new Thread(new Worker(startSignal, doneSignal)).start(); Thread.sleep(1000); startSignal.countDown(); // 打开startSignal开关,执行所有等待的任务 doneSignal.await();// 等待doneSignal计数器为0,即所有任务执行完 System.out 4000 .println("down"); } } class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run() { try { System.out.println(Thread.currentThread().getName() + "启动了"); startSignal.await();// 使当前线程在锁存器startSignal倒计数至零之前一直等待 System.out.println(Thread.currentThread().getName() + "工作了"); doneSignal.countDown();// 递减锁存器doneSignal的计数 } catch (InterruptedException ex) { } } }
执行结果为:
Thread-2启动了
Thread-0启动了
Thread-1启动了
Thread-3启动了
Thread-4启动了
Thread-2工作了
Thread-3工作了
Thread-1工作了
Thread-4工作了
Thread-0工作了
down
从结果中看到,5个任务线程依次启动,但每一个都没有执行完,这是因为run方法中的
startSignal.await();使当前线程在锁存器startSignal倒计数至零之前一直等待。直到
startSignal.countDown();打开startSignal开关,才执行所有等待的任务。
例2:CountDownLatch分割任务
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Driver2 { public static void main(String args[]) throws InterruptedException { int n = 5; ExecutorService exec = Executors.newCachedThreadPool(); // 完成信号,它允许driver在完成所有 worker之前一直等待。 CountDownLatch doneSignal = new CountDownLatch(n); // 创建并启动所有线程 for (int i = 0; i < n; ++i) exec.execute(new WorkerRunnable(doneSignal, i)); // 等待doneSignal计数器为0,即所有任务执行完 doneSignal.await(); System.out.println("down"); exec.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() { System.out.println("任务" + i + "完成了"); doneSignal.countDown();// 递减锁存器doneSignal的计数 } }
源码
待补充
本文就讲到这里,想了解Java并发编程更多内容请参考:
Java并发编程札记-目录
相关文章推荐
- Java并发编程札记-(四)JUC锁-01概述
- Java并发编程札记-(三)JUC原子类-06JDK1.8新增:LongAdder、DoubleAdder、LongAccumulator、DoubleAccumulator
- Java并发编程札记-(六)JUC线程池-02ThreadPoolExecutor实现原理
- Java并发编程札记-(五)JUC容器-06LinkedBlockingDeque
- Java并发编程札记-(六)JUC线程池-05ExecutorCompletionService
- Java并发编程札记-(四)JUC锁-03AQS
- Java并发编程札记-(三)JUC原子类-04原子方式更新引用
- Java并发编程札记-(五)JUC容器-01概述
- Java并发编程札记-(三)JUC原子类-02原子方式更新单个变量
- Java并发编程札记-(四)JUC锁-05ReentrantReadWriteLock简介
- Java并发编程札记-(四)JUC锁-09CyclicBarrier
- Java并发编程札记-(三)JUC原子类-01概述
- Java并发编程札记-(四)JUC锁-04Condition简介
- Java并发编程札记-(四)JUC锁-10Semaphore简介
- Java并发编程札记-(五)JUC容器-02CopyOnWrite
- Java并发编程札记-(一)基础-01基本概念
- Java并发编程札记-(一)基础-06synchronized详解
- Java并发编程札记-(一)基础-05线程安全问题
- Java并发编程札记-(一)基础-04Thread详解
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition