CountDownLatch介绍
java.util.concurrent.CountDownLatch,我们可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。
可以为CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。
应用场景
CountDownLatch的一个非常典型的应用场景是:有一个任务A想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如想要继续往下执行的任务A调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务A将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。CountDownLatch 以一个给定的数量初始化。countDown() 每被调用一次,这 一数量就减一。
举例:
假设有老板和3个工人的雇佣关系,只有等3个工人的工作完成以后,老板才会结束工作完成情况的检查。
1 package com.test.lesson01; 2 3 import java.util.concurrent.CountDownLatch; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.Executors; 6 7 public class Demo3 { 8 public static void main(String[] args) { 9 ExecutorService executorService= Executors.newFixedThreadPool(4); 10 CountDownLatch countDownLatch=new CountDownLatch(3); 11 Worker worker1=new Worker(countDownLatch,"w1"); 12 Worker worker2=new Worker(countDownLatch,"w2"); 13 Worker worker3=new Worker(countDownLatch,"w3"); 14 Boss boss=new Boss(countDownLatch); 15 executorService.execute(worker1); 16 executorService.execute(worker2); 17 executorService.execute(worker3); 18 executorService.execute(boss); 19 executorService.shutdown(); 20 } 21 } 22 23 24 25 class Worker implements Runnable{ 26 private CountDownLatch countDownLatch; 27 private String name; 28 public Worker(CountDownLatch countDownLatch,String name){ 29 this.countDownLatch=countDownLatch; 30 this.name=name; 31 } 32 33 @Override 34 public void run() { 35 try{ 36 Thread.sleep(1000); 37 System.out.println("------开始干活啦-------"); 38 Thread.sleep(500); 39 }catch(InterruptedException e){ 40 e.printStackTrace(); 41 } 42 System.out.println("-----工人"+name+"干活结束----"); 43 countDownLatch.countDown(); 44 } 45 } 46 47 48 class Boss implements Runnable{ 49 private CountDownLatch countDownLatch; 50 public Boss(CountDownLatch countDownLatch){ 51 this.countDownLatch=countDownLatch; 52 } 53 54 @Override 55 public void run() { 56 System.out.println("老板正在等待所有的工人完工"); 57 try { 58 countDownLatch.await();//等待所有和countDown有关的线程执行完毕后才执行本线程 59 } catch (InterruptedException e) { 60 e.printStackTrace(); 61 } 62 System.out.println("老板检查工人完工情况结束"); 63 } 64 }View Code
运行结果之一为:(工人工作的先后顺序可能每次运行不一致,但是“老板检查工人完工情况结束”一定是最后完成)
1 老板正在等待所有的工人完工 2 ------开始干活啦------- 3 ------开始干活啦------- 4 ------开始干活啦------- 5 -----工人w1干活结束---- 6 -----工人w3干活结束---- 7 -----工人w2干活结束---- 8 老板检查工人完工情况结束View Code
如果上述countDownLatch的初始化数量由3改为5,将会线程阻塞,其中一种运行情况为: