CountdownLatch简介
CountDownLatch作用
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能,CountDownLatch可以用来进行线程同步协作,等待所有线程完成倒计时。CountDownLatch内部会维护一个初始值为线程数量的计数器,主线程执行await方法,如果计数器大于0,则阻塞等待。当一个线程完成任务后,计数器值减1。当计数器为0时,表示所有的线程已经完成任务,等待的主线程被唤醒继续执行。
主要方法
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行await();//作用同上面方法,只是增加了超时限制await( longtimeout, TimeUnit unit);//将维护的count值减1countDown();
CountdownLatch的使用
效果演示
public static void m1() throws InterruptedException {CountDownLatch latch = new CountDownLatch(3);new Thread(() -> {log.debug("begin...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());}).start();new Thread(() -> {log.debug("begin...");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());}).start();new Thread(() -> {log.debug("begin...");try {Thread.sleep(1500);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());}).start();log.debug("waiting...");latch.await();log.debug("wait end...");}
运行这个方法,运行结果:
可以看到main线程中调用“latch.await()”确实在等待计数器清零才继续运行。从运行效果来看,这个CountDownLatch的方法似乎和Thread类的join方法没有什么区别,但是如果考虑线程池的情况:固定线程池中的非救急线程是不会停止运行的,他会一直处于活跃状态,因此如果使用join方法就不行了,这时候就体现了计数器的强大之处了,如下面代码:
public static void m2() {CountDownLatch latch = new CountDownLatch(3);ExecutorService service = Executors.newFixedThreadPool(4);service.submit(() -> {log.debug("begin...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());});service.submit(() -> {log.debug("begin...");try {Thread.sleep(1500);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());});service.submit(() -> {log.debug("begin...");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();log.debug("end...{}", latch.getCount());});//用于提交任务的线程service.submit(() -> {try {log.debug("waiting...");latch.await();log.debug("wait end...");} catch (InterruptedException e) {e.printStackTrace();}});}
加载游戏小案例
public static void m3() throws InterruptedException {AtomicInteger num = new AtomicInteger(0);ExecutorService service = Executors.newFixedThreadPool(10, (r) -> {return new Thread(r, "t" + num.getAndIncrement());});CountDownLatch latch = new CountDownLatch(10);String[] all = new String[10];Random r = new Random();for (int j = 0; j < 10; j++) {int x = j;service.submit(() -> {for (int i = 0; i <= 100; i++) {try {Thread.sleep(r.nextInt(100));} catch (InterruptedException e) {}all[x] = Thread.currentThread().getName() + "(" + (i + "%") + ")";System.out.print("\r" + Arrays.toString(all));}latch.countDown();});}latch.await();System.out.println("\n游戏开始...");service.shutdown();}


