非主流并发工具之 CountDownLatch

CountDownLatch 是一个用来倒计数的咚咚。如果某项任务可以拆分成若干个子任务同时进行,然后等待所有的子任务完成,可以考虑使用它。

该类的用法非常简单。首先构造一个 CountDownLatch,唯一的参数是任务数量,一旦构造完毕就不能修改。接着启动所有的子任务(线程),且每个子任务在完成自己的计算后,调用 CountDownLatch#countDown 方法将倒计数减一。最后在主线程中调用 CountDownLatch#await 方法等待计数器归零。

例如赛跑的准备阶段,八名运动员先后到达起点做好准备,然后裁判打响发令枪,准备工作就结束了,比赛开始。如果把从运动员就位到发令枪响看做赛跑准备任务,那么每个运动员的准备过程就是其子任务,可以用 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
final int count = 8;
System.out.println("运动员开始就位。");
 
// 构造 CountDownLatch。
final CountDownLatch cdl = new CountDownLatch(count);
for (int i = 1; i <= count; i++) {
    final int number = i;
    new Thread() {
        @Override
        public void run() {
            System.out.println(number + " 号运动员到场并开始准备...");
            try {
                // 让运动员随机准备 2~5 秒钟。
                TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2);
            } catch (InterruptedException ex) {
            }
            System.out.println(number + " 号运动员就位。");
            // 倒计数减一。
            cdl.countDown();
        }
    }.start();
}
 
System.out.println("等待所有运动员就位...");
try {
    // 等待倒计数变为 0。
    cdl.await();
    System.out.println("比赛开始。");
} catch (InterruptedException ex) {
}

运行输出(可能)为:

运动员开始就位。
1 号运动员到场并开始准备...
2 号运动员到场并开始准备...
4 号运动员到场并开始准备...
等待所有运动员就位...
8 号运动员到场并开始准备...
6 号运动员到场并开始准备...
3 号运动员到场并开始准备...
7 号运动员到场并开始准备...
5 号运动员到场并开始准备...
6 号运动员就位。
1 号运动员就位。
5 号运动员就位。
4 号运动员就位。
7 号运动员就位。
8 号运动员就位。
2 号运动员就位。
3 号运动员就位。
比赛开始。

从上面的例子还可以看出 CountDownLatch 的局限性和 CompletionService 类似,在于无法处理子任务数量不确定的情况,例如统计某个文件夹中的文件数量。另外,如果某个子任务在调用 countDown 之前就挂掉了,倒计数就永远不会归零。对于这种情况,要么用 finally 之类的手段保证 countDown 一定会被调用,要么用带参数的 await 方法指定超时时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值