1 CountDownLatch
1.1 含义
一种同步辅助,允许一个或多个线程等待一组正在其他线程中执行的操作完成。CountDownLatch使用给定的计数进行初始化。由于对countDown方法的调用,await方法会阻塞,直到当前计数为零,在此之后,所有正在等待的线程都会被释放,后续对await的调用会立即返回。这是一种一次性现象——计数无法重置。如果需要重置计数的版本,可以考虑使用CyclicBarrier。
CountDownLatch是一个通用的同步工具,可以用于许多目的。初始化计数为1的CountDownLatch作为一个简单的打开/关闭锁:所有调用await的线程都在门上等待,直到它被调用countDown的线程打开。初始化为N的CountDownLatch可以用来让一个线程等待,直到N个线程完成某个动作,或者某个动作已经完成N次。
CountDownLatch的一个有用属性是,它不要求调用countDown的线程等待计数达到0后再继续,它只是阻止任何线程通过await,直到所有线程都可以通过。
1.2 使用场景举例
公司要选择一个办公室开董事会,董事会共有股东十个人,需要等每个股东都要到办公室才能开会,我们把每个股东视为一个线程,把开会这个事件视为主线程。
1.3 代码实现
/** * @desc: JUC CountDownLatch应用场景 * @author: YanMingXin * @create: 2021/7/31-10:24 **/ public class Test01 { public static void main(String[] args) throws InterruptedException { //公司开会需要集齐董事会10个人,10个人不分先后,只要来齐了才能开会 CountDownLatch latch = new CountDownLatch(10); //十个人每个人一个线程 for (int i = 0; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + "到场"); //增加一个人 latch.countDown(); }, String.valueOf(i)).start(); } //主线程等待 latch.await(); System.out.println("开始开会......"); } } 复制代码
测试结果
2 CyclicBarrier
2.1 含义
一种同步辅助,它允许一组线程都等待彼此到达一个共同的障碍点。CyclicBarrier在涉及固定大小的线程的程序中非常有用,这些线程偶尔必须相互等待。这个屏障被称为循环屏障,因为在等待的线程被释放后,它可以被重用。
CyclicBarrier支持一个可选的Runnable命令,该命令在每个barrier点运行一次,在该组的最后一个线程到达之后,但在任何线程被释放之前。这个barrier操作对于在任何一方继续之前更新共享状态非常有用。
2.2 使用场景举例
公司开完董事会后,为了保证安全性需要将办公室锁起来,当然锁门之前需要每个人都要走出来,我们仍旧把每个人当作一个线程,把锁门的事件当做主线程。
2.3 代码实现
/** * @desc: JUC CyclicBarrier * @author: YanMingXin * @create: 2021/7/31-10:31 **/ public class Test02 { public static void main(String[] args) { //公司董事会开完会要等全部出去才能锁门 CyclicBarrier barrier = new CyclicBarrier(10, () -> { System.out.println("办公室锁门......"); }); for (int i = 1; i <= 10; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName()); try { //等待锁门 barrier.await(); } catch (Exception e) { e.printStackTrace(); } }, String.valueOf(i)).start(); } } } 复制代码
测试结果:
3 结语
当然以上的使用场景是最常见的,以后有时间的话还要研究下CountDownLatch和CyclicBarrier的其他使用场景和原理,敬请期待哦!