为了解决多线程问题,java.util.concurrent包从Java SE5开始引入了一个新类CountDownLatch。其功能主要用来同步多个任务的执行顺序,CountDown的意思是倒数计秒,Latch做为名词有门闩和锁存器的意思。
锁存器的最主要作用是缓存,其次完成高速的控制其与慢速的外设的不同步问题,再其次是解决驱动的问题,最后是解决一个 I/O 口既能输出也能输入的问题。
因此,顾名思义,CountDownLatch可以在倒数计时期间保持多个任务的执行状态,倒计时结束时便可以解锁并唤醒其他任务。
CountDownLatch最典型的应用就是将一个大的任务分解成N个子任务,当N个子任务执行完毕后可以唤起下一个大任务。
我们将N作为倒数记时的时间来初始化一个CoutDownLatch对象,然后每当一个子任务完成时,可以将N减1,等到N为0的时候,其他正在等待的任务便可以wake up。
Package
import java.util.concurrent.*;
首先,定义一个子任务TaskPortion
private static Random rand = new Random(47);
private final CountDownLatch latch;
TaskPortion(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
try {
doWork();
latch.countDown();
} catch (InterruptedException e) {
// Acceptable way to exit
}
}
public void doWork() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
System.out.println(this + "completed");
}
public String toString() {
return String.format("%1$-3d", id);
}
}
然后,定义一个不同的任务,但是这个任务只有在所有子任务全部完成后才可以执行。
// Waits on the CountDownLatch
class WaitingTask implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final CountDownLatch latch;
WaitingTask(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
try {
latch.await();
System.out.println("Latch barrier passed for " + this);
} catch (InterruptedException ex) {
System.out.println(this + " interrupted");
}
}
public String toString() {
return String.format("WaitingTask %1$-3d ", id);
}
}
最后,编写测试代码,通过new 100个TaskPortion来分解一个大的任务,新建10个需要等待的任务。
public class CountDownLatchDemo {
static final int SIZE = 10;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
// All must share a single CountDownLatch object:
CountDownLatch latch = new CountDownLatch(SIZE);
for (int i = 0; i < 10; i++) {
exec.execute(new WaitingTask(latch));
}
for (int i = 0; i < SIZE; i++) {
exec.execute(new TaskPortion(latch));
}
System.out.println("Launched all tasks");
exec.shutdown(); // Quit when all tasks complete
}
}
编译后执行,结果如下。可以看出只有当10个TaskPortion结束之后,WaitingTask才可以继续执行。
Launched all tasks
7 completed
9 completed
5 completed
8 completed
1 completed
2 completed
6 completed
4 completed
0 completed
3 completed
Latch barrier passed for WaitingTask 7
Latch barrier passed for WaitingTask 9
Latch barrier passed for WaitingTask 2
Latch barrier passed for WaitingTask 5
Latch barrier passed for WaitingTask 8
Latch barrier passed for WaitingTask 4
Latch barrier passed for WaitingTask 6
Latch barrier passed for WaitingTask 0
Latch barrier passed for WaitingTask 3
Latch barrier passed for WaitingTask 1