JUC之CountDownLatch

CountDownLatch简介

一个线程需要等到其他线程进行某操作后在运行,可以使用CountDownLatch。

CountDownLatch构造方法,带有一个int类型的参数。

1
public CountDownLatch(int count)

当一个线程调用countDownLatch.await()时,线程会等待。直到其他线程执行
countDownLatch.countDown()。每执行一个countDown方法,初始化的count会减一,直到count=0时,等待线程才被唤醒。

使用

假设场景顾客餐厅吃饭,需要等待做饭,炒菜,上汤都完成了,才开始吃饭。
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//顾客线程
public class Customer implements Runnable {

private final CountDownLatch countDownLatch;

public Customer(CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
}
public void run() {
System.out.println("点完菜,等待开吃");
try {
this.countDownLatch.await();
System.out.println("开饭了。。。。。。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}


}

public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(3);

Thread customer = new Thread(new Customer(countDownLatch));
//顾客进餐厅点菜
customer.start();

new Thread(){
@Override
public void run() {
try {
System.out.println("做饭");
}finally {
countDownLatch.countDown();
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
System.out.println("炒菜");
}finally {
countDownLatch.countDown();
}
}
}.start();

new Thread(){
@Override
public void run() {
try {
System.out.println("上汤");
}finally {
countDownLatch.countDown();
}
}
}.start();

customer.join();
}

输出:

1
2
3
4
5
点完菜,等待开吃
做饭
炒菜
上汤
开饭了。。。。。。。。

结果正确,等待做饭,炒菜,上汤都完成了,才开始吃饭。

总结

  1. countDownLatch内部通过共享锁实现
  2. countDown方法最好放在finally代码块中执行,防止线程永远等待
  3. CountDownLatch再 count减到0之后,再次执行countDown不会有影响,count不变。
  4. await方法有重载方法
    public boolean await(long timeout, TimeUnit unit),等待一段时间后恢复。
  5. countDownLatch只能使用一次,count=0时,不能回滚再次使用。