并发类编程—CountDownLatch(同步器)
1、概述
CountDownLatch是一个同步器工具类,用来协调多个线程之间的同步,能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行,不可重置使用。
2、实现
使用一个计数器进行实现,计数器初始值为线程的数量,当每一个线程完成自己任务后,计数器的值就会减一,当计数器的值为0时,在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
3、缺点
CountDownLatch是一次性的,计算器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。
4、方法说明:
- public void countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
- public viod await() /boolean await(long timeout,TimeUnit unit) :使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。当线程调用了CountDownLatch对象的该方法后,当前线程会被阻塞,直到下面的情况之一发生才会返回:
- 如果计数到达零,则该方法返回true值。
- 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
- 如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。参数:timeout-要等待的最长时间、unit-timeout 参数的时间单位
5、使用用法
- 某一线程在开始运行前等待n个线程执行完毕
- 多个线程开始执行任务的最大并行性(多个线程等待一个线程执行完成)
5.1 方法一
某一线程在开始运行前等待n个线程执行完毕,为某一个线程设置await(),当CountDownLatch为0时,执行当前线程。
public class Test { / * 设置计数器大小为5 */ private static CountDownLatch latch = new CountDownLatch(5); public static void loading(int num) { System.out.println("计数器数量为:" + num); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); } public static void main(String[] args) { new Thread(() -> { for (int i = 5; i >= 1; i--) { loading(i); } }, "t1").start(); // 等待5个t1线程执行完成 try { latch.await(); System.out.println("执行主线程"); } catch (InterruptedException e) { e.printStackTrace(); } }}
效果:
5.2 方法二
实现多个线程开始执行任务的最大并行性,比如设置CountDownLatch()初始化值为1,多个线程同时进行countdownlatch.await(),到计数器值为0时多个线程同时运行(多个线程等待其他线程执行完成后再执行)。
public class Test { / * 设置计数器大小为1 */ private static CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) { for (int i = 5; i >= 1; i--) { new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + "-准备中"); latch.await(); System.out.println(Thread.currentThread().getName() + "-已完成"); } catch (Exception e) { e.printStackTrace(); } }).start(); } // 等待一秒,让其他线程做好准备 try { TimeUnit.SECONDS.sleep(1); System.out.println("执行主线程"); latch.countDown(); } catch (Exception e) { e.printStackTrace(); } }}
效果: