JUC三大辅助类CountDownLatch、CyclicBarrier和Semaphore详解
作者:帅气的喵喵
JUC 中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过多时 Lock 锁的频繁操作。
这三种辅助类为:
CountDownLatch: 减少计数
CyclicBarrier: 循环栅栏
Semaphore: 信号灯
减少计数 CountDownLatch
CountDownLatch 类可以设置一个计数器,然后通过 countDown 方法来进行 减 1 的操作,使用 await 方法等待计数器不大于 0,然后继续执行 await 方法 之后的语句。
- CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,这 些线程会阻塞
- 其它线程调用 countDown 方法会将计数器减 1(调用 countDown 方法的线程 不会阻塞)
- 当计数器的值变为 0 时,因 await 方法阻塞的线程会被唤醒,继续执行
场景: 6 个同学陆续离开教室后值班同学才可以关门。
//演示 CountDownLatch public class CountDownLatchDemo { //6个同学陆续离开教室之后,班长锁门 public static void main(String[] args) throws InterruptedException { //创建CountDownLatch对象,设置初始值 CountDownLatch countDownLatch = new CountDownLatch(6); //6个同学陆续离开教室之后 for (int i = 1; i <=6; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+" 号同学离开了教室"); //计数器减一,不会阻塞 countDownLatch.countDown(); },String.valueOf(i)).start(); } //主线程 await 休息 countDownLatch.await(); //全部离开后自动唤醒主线程 是指计数器不大于 0,然后继续执行 await 方法之后的语句。 System.out.println("全部离开了,现在的计数器为" + countDownLatch.getCount()); System.out.println(Thread.currentThread().getName()+" 班长锁门走人了"); } }
循环栅栏 CyclicBarrier.
CyclicBarrier 看英文单词可以看出大概就是循环阻塞的意思,在使用中CyclicBarrier 的构造方法第一个参数是目标障碍数,每次执行 CyclicBarrier 一 次障碍数会加一,如果达到了目标障碍数,才会执行 cyclicBarrier.await()之后 的语句 。可以将 CyclicBarrier 理解为加 1 操作
常用的构造方法有:
CyclicBarrier(int parties,Runnable barrierAction)创建一个新的CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动barrier时执行给定的屏障操作,该操作由最后一个进入barrier的线程操作
常用的方法有:
await() 在所有的参与者都已经在此barrier上调用await方法之前一直等待
场景: 集齐 7 颗龙珠就可以召唤神龙
//集齐7颗龙珠就可以召唤神龙 public class CyclicBarrierDemo { //创建固定值 private static final int NUMBER = 7; public static void main(String[] args) { //创建CyclicBarrier CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER,()->{ System.out.println("*****集齐7颗龙珠就可以召唤神龙"); }); //集齐七颗龙珠过程 for (int i = 1; i <=7; i++) { new Thread(()->{ try { System.out.println(Thread.currentThread().getName()+" 星龙被收集到了"); //等待 cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } },String.valueOf(i)).start(); } } }
信号灯 Semaphore
Semaphore 的构造方法中传入的第一个参数是最大信号量(可以看成最大线程池),每个信号量初始化为一个最多只能分发一个许可证。
使用 acquire 方法获得许可证 , release 方法释放许可
场景: 抢车位, 6 部汽车 3 个停车位
具体常用的构造方法有:Semaphore(int permits)创建具有给定的许可数和非公平的公平设置的Semapore
具体常用的方法有:acquire()从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断release() 释放一个许可,将其返回给信号量
设置许可数量Semaphore semaphore = new Semaphore(3); 一般acquire()都会抛出异常,release在finally中执行
//6辆汽车,停3个车位 public class SemaphoreDemo { public static void main(String[] args) { //创建Semaphore,设置许可数量 Semaphore semaphore = new Semaphore(3); //模拟6辆汽车 for (int i = 1; i <=6; i++) { new Thread(()->{ try { //抢占 semaphore.acquire(); System.out.println(Thread.currentThread().getName()+" 抢到了车位"); //设置随机停车时间 TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println(Thread.currentThread().getName()+" ------离开了车位"); } catch (InterruptedException e) { e.printStackTrace(); } finally { //释放 semaphore.release(); } },String.valueOf(i)).start(); } } }
到此这篇关于JUC三大辅助类CountDownLatch、CyclicBarrier和Semaphore详解的文章就介绍到这了,更多相关CountDownLatch、CyclicBarrier和Semaphore内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!