CountDownLatch主要用于同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。
你可以向CountDownLatch对象设置一个初始计数值,任何在这个对象上调用wait()的方法都将阻塞,直到这个计数值达到0.其他任务在结束其工作时,可以在该对象上调用countDown()来减小这个计数值,你可以通过调用getCount()方法来获取当前的计数值。CountDownLatch被设计为只触发一次,计数值不能被重置。如果你需要能够重置计数值的版本,则可以使用CyclicBarrier。
调用countDown()的任务在产生这个调用时并没有阻塞,只有对await()的调用会被阻塞,直到计数值到达0。
CountDownLatch的典型用法是将一个程序分为n个互相独立的可解决人物,并创建值为0的CountDownLatch。当每个任务完成是,都会在这个锁存器上调用countDown()。等待问题被解决的任务在这个锁存器上调用await(),将它们自己锁住,直到锁存器计数结束。下面是演示这种技术的一个框架示例:
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class TaskPortion implements Runnable {
private static int counter = 0;
private final int id = counter++;
private static Random random = new Random();
private final CountDownLatch latch;
public TaskPortion(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
doWork();
latch.countDown();//普通任务执行完后,调用countDown()方法,减少count的值
System.out.println(this + " completed. count=" + latch.getCount());
} catch (InterruptedException e) {
}
}
public void doWork() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
}
@Override
public String toString() {
return String.format("%1$-2d ", id);
}
}
class WaitingTask implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final CountDownLatch latch;
public WaitingTask(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
//这些后续任务需要等到之前的任务都执行完成后才能执行,即count=0时
latch.await();
System.out.println("Latch barrier passed for " + this);
} catch (InterruptedException e) {
System.out.println(this + " interrupted.");
}
}
@Override
public String toString() {
return String.format("WaitingTask %1$-2d ", id);
}
}
public class CountDownLatchDemo {
static final int SIZE = 10;
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(SIZE);
ExecutorService exec = Executors.newCachedThreadPool();
//10个WaitingTask
for (int i = 0; i < 5; i++) {
exec.execute(new WaitingTask(latch));
}
//100个任务,这100个任务要先执行才会执行WaitingTask
for (int i = 0; i < SIZE; i++) {
exec.execute(new TaskPortion(latch));
}
System.out.println("Launched all tasks.");
exec.shutdown();//当所有的任务都结束时,关闭exec
}
}
执行结果(可能的结果):
Launched all tasks. 4 completed. count=9 6 completed. count=8 3 completed. count=7 0 completed. count=6 2 completed. count=5 1 completed. count=4 5 completed. count=3 7 completed. count=2 9 completed. count=1 8 completed. count=0 Latch barrier passed for WaitingTask 0 Latch barrier passed for WaitingTask 2 Latch barrier passed for WaitingTask 1 Latch barrier passed for WaitingTask 3 Latch barrier passed for WaitingTask 4
从结果中可以看到,所有的WaitingTask都是在所有的TaskPortion执行完成之后执行的。
TaskPortion将随机的休眠一段时间,以模拟这部分工作的完成。而WaitingTask表示系统中必须等待的部分,它要等到问题的初始部分完成后才能执行。注意:所有任务都使用了在main()中定义的同一个CountDownLatch对象。
原文:http://my.oschina.net/itblog/blog/516282