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