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: