concurrent并发包之CountDownLatch

CountDownLatch实际上是一种闭锁实现。闭锁:是一种同步工具类,可以延迟线程的进度知道其到达终止状态——《Java并发编程实战》。这个怎么解释呢?简单来说,就是有1个线程需要等待其余10个线程都执行完毕后再执行,这个时候就可以使用闭锁,也即CountDownLatch(当然闭锁的实现并不止这一种)。关于对闭锁的详细解释请参考《Java并发编程实战》P79。

CountDownLatch中有一个计数器,该计数器通过构造方法传递,表示需要完成的工作。有两个主要的方法:countDown——表示计数器减1,再完成一个工作时调用此方法。await——表示唤醒,等待线程在执行方法前调用此方法,当计数器未为0(即还有工作尚未完成)时,被阻塞,当所有工作都已完成,计数器被减至0,此时等待线程才被唤醒以继续执行。

我们通过代码来实际感受一下CountDownLatch类API的使用。

首先有一个TaskThread任务线程,表示做好准备工作的线程。

 1 package countdownlatch;
 2
 3 import java.util.concurrent.CountDownLatch;
 4
 5 /**
 6  * Created by yulinfeng on 12/14/16.
 7  */
 8 public class TaskThread implements Runnable {
 9     private final CountDownLatch latch;
10
11     public TaskThread(CountDownLatch latch){
12         this.latch = latch;
13     }
14
15     @Override
16     public void run() {
17         try {
18             doWork();
19             latch.countDown();  //线程执行完这部分工作后,CountDownLatch的计数减1。
20         } catch (InterruptedException e) {
21             e.printStackTrace();
22         }
23     }
24
25     private void doWork() throws InterruptedException{
26         System.out.println(Thread.currentThread().getName());
27         Thread.sleep(2000);  //休眠2s,模拟这部分工作的完成
28     }
29 }

接着是等待线程,即当所有的TaskThread完成各自的工作之后再执行此线程。

 1 package countdownlatch;
 2
 3 import java.util.concurrent.CountDownLatch;
 4
 5 /**
 6  * Created by yulinfeng on 12/14/16.
 7  */
 8 public class WaitThread implements Runnable{
 9     private final CountDownLatch latch;
10
11     public WaitThread(CountDownLatch latch){
12         this.latch = latch;
13     }
14
15     @Override
16     public void run() {
17         try {
18             System.out.println("Wait for other threads to execute!");   //就算CPU在未完成所有TaskThread进入到次线程,该线程也会因为CountDownLatch计数器未减至0而阻塞。
19             latch.await();  //直到CountDownLatch的计数器减至0(即表示所有的工作也完成)才继续执行,否则阻塞。
20             System.out.println("Other threads have already completed!");
21         } catch (InterruptedException e) {
22             e.printStackTrace();
23         }
24
25     }
26 }

测试代码:

 1 package countdownlatch;
 2
 3 import java.util.concurrent.CountDownLatch;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6
 7 /**
 8  * Created by yulinfeng on 12/14/16.
 9  */
10 public class Test {
11
12     public static void main(String[] args){
13         ExecutorService exec = Executors.newCachedThreadPool();
14         CountDownLatch latch = new CountDownLatch(100);     //所有线程必须共享一个CountDownLatch单例(这也是在另外两个线程中CountDownLatch定义为final不可变引用的原因),模拟有100个工作待完成。
15
16         exec.execute(new WaitThread(latch));    //等待线程
17         for (int i = 0; i < 100; i++){
18             exec.execute(new TaskThread(latch));    //开启100个线程,模拟完成100个工作。
19         }
20
21         exec.shutdown();
22     }
23 }

执行结果很好的诠释了CountDownLatch:

时间: 2024-10-08 10:34:36

concurrent并发包之CountDownLatch的相关文章

Java学习笔记—多线程(java.util.concurrent并发包概括,转载)

一.描述线程的类:Runable和Thread都属于java.lang包 二.内置锁synchronized属于jvm关键字,内置条件队列操作接口Object.wait()/notify()/notifyAll()属于java.lang包 二.提供内存可见性和防止指令重排的volatile属于jvm关键字 四.而java.util.concurrent包(J.U.C)中包含的是java并发编程中有用的一些工具类,包括几个部分: 1.locks部分:包含在java.util.concurrent.

java.util.concurrent并发包诸类概览

java.util.concurrent包的类都来自于JSR-166:Concurrent Utilities,官方的描述叫做“The JSR proposes a set of medium-level utilities that provide functionality commonly needed in concurrent programs. ”.作者是大名鼎鼎的Doug Lea,这个包的前身可以在这里找到,它最好的文档就是系统的API手册. 当然,这里参考的concurrent包

Java集合及concurrent并发包总结

1.集合包 集合包最常用的有Collection和Map两个接口的实现类,Colleciton用于存放多个单对象,Map用于存放Key-Value形式的键值对. Collection中最常用的又分为两种类型的接口:List和Set,两者最明显的差别为List支持放入重复的元素,而Set不支持. List最常用的实现类有:ArrayList.LinkedList.Vector及Stack:Set接口常用的实现类有:HashSet.TreeSet. 1.1 ArrayList ArrayList基于

Java并发包中CountDownLatch的工作原理、使用示例

1. CountDownLatch的介绍 CountDownLatch是一个同步工具,它主要用线程执行之间的协作.CountDownLatch 的作用和 Thread.join() 方法类似,让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒.在直接创建线程的年代(Java 5.0 之前),我们可以使用 Thread.join().在线程池出现后,因为线程池中的线程不能直接被引用,所以就必须使用 CountDownLatch 了. CountDownLatch主要有两个方法,当一个或多个线程调

Java集合及concurrent并发包总结(转)

1.集合包 集合包最常用的有Collection和Map两个接口的实现类,Colleciton用于存放多个单对象,Map用于存放Key-Value形式的键值对. Collection中最常用的又分为两种类型的接口:List和Set,两者最明显的差别为List支持放入重复的元素,而Set不支持. List最常用的实现类有:ArrayList.LinkedList.Vector及Stack:Set接口常用的实现类有:HashSet.TreeSet. 1.1 ArrayList ArrayList基于

java.util.concurrent常用类(CountDownLatch,Semaphore,CyclicBarrier,Future)

CyclicBarrier CyclicBarrier是用来一个关卡来阻挡住所有线程,等所有线程全部执行到关卡处时,再统一执行下一步操作.假设一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发,只要有一个人没有准备好,大家就等待 . 代码示例: public class UseCyclicBarrier { static class Runner implements Runnable { private CyclicBarrier barrier; private Strin

Java并发包(1):CountDownLatch、CyclicBarrier、Semaphore

1.CountDownLatchCountDownLatch.wait()会使当前线程阻塞,直到CountDownLatch中的计数器递减完毕后继续执行. public class CountDownLatchDemo { private final static Logger log = Logger.getLogger(AtomicIntegerCyclicBarrierDemo.class); public static void main(String[] args) { final C

「java.util.concurrent并发包」之 ThreadPool

一 异步用new Thread? 大些的"low"!! new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 你还在上面这么用吗,太low 了.弊端多多: 1.  每次new Thread新建对象性能差. 2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. 3. 缺乏更多功能,如定

「java.util.concurrent并发包」之 ReentrantReadWriteLock

一 引言 在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题.比如在一个线程读取数据的时候,另外一个线程在写数据,而导致前后数据的不一致性:一个线程在写数据的时候,另一个线程也在写,同样也会导致线程前后看到的数据的不一致性.这时候可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这样是可以解决这样以上的问题,但是效率却大打折扣了.因为在真实的业务场景中,一份数据,读取数据的操作次数通常高于写入数据的操作,而线程与线程间的读读操作是不涉