Java的concurrent包里面的CountDownLatch其实可以被看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。
可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。主要方法public CountDownLatch(int count)public void countDown()public void await() throws InterruptedException 构造方法参数指定了计数的次数countDown方法,当前线程调用此方法,则计数减一awaint方法,调用此方法会一直阻塞当前线程,直到计时器的值为0例如有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。public class Boss implements Runnable{ private final CountDownLatch countDownLatch;private String name;public Boss(String name, CountDownLatch countDownLatch){ super();this.name = name;this.countDownLatch = countDownLatch;}public void run(){ try{ System.out.println("老板" + name + "正在等工人把活干完");countDownLatch.await();System.out.println("工人活都干完了,老板开始检查了!");}catch (InterruptedException e){ e.printStackTrace();}}}public class Worker implements Runnable{ private final CountDownLatch countDownLatch;private String name;public Worker(String name, CountDownLatch countDownLatch){ super();this.name = name;this.countDownLatch = countDownLatch;}public void run(){ doWork();countDownLatch.countDown();}private void doWork(){ try{ System.out.println(this.name + "正在干活!");long duration = new Random().nextInt(5) * 1000;Thread.sleep(duration);System.out.println(this.name + "活干完啦!");}catch (InterruptedException e){ e.printStackTrace();}}}public class BossWorkerTest{ public static void main(String[] args){ ExecutorService executor = Executors.newCachedThreadPool();CountDownLatch countDownLatch = new CountDownLatch(3);Worker w1 = new Worker("张一", countDownLatch);Worker w2 = new Worker("张二", countDownLatch);Worker w3 = new Worker("张三", countDownLatch);Boss boss = new Boss("王老板", countDownLatch);executor.execute(w3);executor.execute(w2);executor.execute(w1);executor.execute(boss);executor.shutdown();}}下面是本地机器上运行的一次结果,每次运行的结果可能与下面不一样,但老板检查永远是在最后面。张三正在干活!张二正在干活!张一正在干活!张三活干完啦!老板王老板正在等工人把活干完张一活干完啦!张二活干完啦!工人活都干完了,老板开始检查了!再看一个例子,该程序用来模拟发送命令与执行命令。主线程代表教练,新建3个线程代表运动员。运动员一直等待着教练下达命令。若教练没有下达命令,则运动员们都必须等待。一旦命令下达,运动员们都去执行自己的任务,教练处于等待状态,运动员们任务执行完毕则报告给教练,教练则结束等待。public class CountdownLatchTest{ public static void main(String[] args){ // 创建一个线程池ExecutorService service = Executors.newCachedThreadPool();// 教练的命令设置为1,教练一下达命令,则countDown变为0,运动员们执行任务final CountDownLatch cdOrder = new CountDownLatch(1);// 因为有三个运动员故初始值为3,每个运动员执行任务完毕则countDown一次// 当三个都执行完毕变为0则教练停止等待
final CountDownLatch cdAnswer = new CountDownLatch(3);for (int i = 0; i < 3; i++){ Runnable runnable = new Runnable(){ public void run(){ try{ System.out.println("线程" + Thread.currentThread().getName() + "正准备接受命令");// 运动员们都处于等待命令状态cdOrder.await();System.out.println("线程" + Thread.currentThread().getName() + "已接受命令");Thread.sleep((long) (Math.random() * 10000));System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果");// 任务执行完毕返回给教练,cdAnswer减1cdAnswer.countDown();}catch (Exception e){ e.printStackTrace();}}};service.execute(runnable);}try{ Thread.sleep((long) (Math.random() * 10000));System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令");// 发送命令cdOrder减1,处于等待的运动员们停止等待转去执行任务cdOrder.countDown();System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果");// 命令发送后教练处于等待状态,一旦cdAnswer为0时停止等待继续往下执行cdAnswer.await();System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果");}catch (Exception e){ e.printStackTrace();}service.shutdown();}}原帖地址:http://zapldy.iteye.com/blog/746458http://www.cnblogs.com/liuling/p/2013-8-20-02.html