Java 5 开始引入的 Concurrent 并发软件包里面的 CountDownLatch 其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。 所以,CountDownLatch类可以用于控制多个线程同时开始运行,或者用于主线程等待所有子线程都结束。
举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:
1 public class Worker implements Runnable{ 2 3 private CountDownLatch downLatch; 4 private String name; 5 6 public Worker(CountDownLatch downLatch, String name){ 7 this.downLatch = downLatch; 8 this.name = name; 9 } 10 11 public void run() { 12 this.doWork(); 13 try 14 { 15 TimeUnit.SECONDS.sleep(new Random().nextInt(10)); 16 }catch(InterruptedException ie){ 17 } 18 System.out.println(this.name + "活干完了!"); 19 this.downLatch.countDown(); 20 21 } 22 23 private void doWork() 24 { 25 System.out.println(this.name + "正在干活!"); 26 } 27 28 } 29 30 ================== 31 32 public class Boss implements Runnable { 33 34 private CountDownLatch downLatch; 35 36 public Boss(CountDownLatch downLatch){ 37 this.downLatch = downLatch; 38 } 39 40 public void run() { 41 System.out.println("老板正在等所有的工人干完活......"); 42 try { 43 this.downLatch.await(); 44 } catch (InterruptedException e) { 45 } 46 System.out.println("工人活都干完了,老板开始检查了!"); 47 } 48 49 } 50 51 52 ============================ 53 54 public class CountDownLatchDemo { 55 56 public static void main(String[] args) { 57 ExecutorService executor = Executors.newCachedThreadPool(); 58 59 CountDownLatch latch = new CountDownLatch(3); 60 61 Worker w1 = new Worker(latch,"张三"); 62 Worker w2 = new Worker(latch,"李四"); 63 Worker w3 = new Worker(latch,"王二"); 64 65 Boss boss = new Boss(latch); 66 67 executor.execute(w3); 68 executor.execute(w2); 69 executor.execute(w1); 70 executor.execute(boss); 71 72 executor.shutdown(); 73 } 74 }