0%

Java 同步和协作工具类(三):倒计时门栓 CountDownLatch

1. 怎样理解倒计时门栓 CountDownLatch

  • 作用就相当于现实生活中的门栓,一开始是关闭的,所有希望通过该门的线程都需要等待,然后开始倒计时,倒计时变为 0 后,门栓打开,等待的所有线程都可以通过
  • 不同的是,它是一次性的,打开后就不能再关上了

2. 门栓的两种应用场景

  • 一种是同时开始,一种是主从协作
  • 它们都有两类线程,互相需要同步

3. 使用 CountDownLatch 实现同时开始(运动员比赛)场景

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
public class RacerWithCountDownLatch {
static class Racer extends Thread {
CountDownLatch latch;

public Racer(CountDownLatch latch) {
this.latch = latch;
}

@Override
public void run() {
try {
this.latch.await();
System.out.println(getName() + " start run " + System.currentTimeMillis());
} catch(InterruptedException e) {

}
}
}

public static void main(String[] args) throws InterruptedException {
int num = 10;
CountDownLatch latch = new CountDownLatch(1);
Thread[] racers = new Thread[num];

for(int i=0; i<num; i++) {
racers[i] = new Racer(latch);
racers[i].start();
}

Thread.sleep(1000);
latch.countDown();
}
}

4. 使用 CountDownLatch 实现主从协作(主线程等待工作线程结束)场景

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
public class MasterWorkerDemo {

static class Worker extends Thread {
CountDownLatch latch;

public Worker(CountDownLatch latch) {
this.latch = latch;
}

@Override
public void run() {
try {
//模拟执行任务
Thread.sleep((int) (Math.random() * 1000));
//模拟异常情况
if(Math.random() < 0.2) {
throw new RuntimeException("bad luck");
}
} catch(InterruptedException e) {

} finally {
this.latch.countDown(); //确保在工作线程发生异常的情况下也会被调用,使主线程能够从 await() 调用中返回
}
}
}

public static void main(String[] args) throws InterruptedException {
int workerNum = 100;
CountDownLatch latch = new CountDownLatch(workerNum);
Worker[] workers = new Worker[workerNum];

for(int i=0; i<workerNum; i++) {
workers[i] = new Worker(latch);
workers[i].start();
}

latch.await();
System.out.println("collect worker results");
}
}
-------------------- 本文结束感谢您的阅读 --------------------