JUC辅助类
JUC 中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过多时Lock锁的频繁操作。这三种辅助类为:
- CountDownLatch: 减少计数
- CyclicBarrier: 循环栅栏
- Semaphore: 信号灯
1. 减少计数CountDownLatch
CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减1的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句。
- CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。
- 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)。
- 当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行。
场景: 6个同学陆续离开教室后值班同学才可以关门
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建CountdownLatch 初始值
CountDownLatch cdl = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "离开了");
// 计数 -1
cdl.countDown();
}, (i+1)+"线程").start();
}
// 等待所有线程执行完毕
cdl.await();
System.out.println("关闭大门");
}
运行结果:
2. 循环栅栏CyclicBarrier
CyclicBarrier看英文单词可以看出大概就是循环阻塞的意思,在使用中CyclicBarrier 的构造方法第一个参数是目标障碍数,每次执行CyclicBarrier一次障碍数会加一,如果达到了目标障碍数,才会执行cyclicBarrier.await()
之后的语句。可以将CyclicBarrier理解为加1操作。
场景: 集齐 7 颗龙珠就可以召唤神龙
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 定义有7颗龙珠
CyclicBarrier cb = new CyclicBarrier(7, ()->{
// 多线程执行完毕进行回调
System.out.println("龙珠已经集齐,召唤神龙");
});
for (int i = 0; i < 7; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "收集到了1个龙珠");
try {
cb.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
}, (i+1)+"线程").start();
}
}
运行结果:
3. 信号灯 Semaphore
Semaphore的构造方法中传入的第一个参数是最大信号量(可以看成最大线程池),每个信号量初始化为一个最多只能分发一个许可证。使用acquire方法获得许可证,release方法释放许可。
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 定义三个停车位
Semaphore sp = new Semaphore(3);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
try {
// 试图抢占车位
sp.acquire(1);
System.out.println(Thread.currentThread().getName() + "抢到了车位");
sp.release(1);
System.out.println(Thread.currentThread().getName() + "离开车位");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, (i+1)+"号汽车").start();
}
}
运行结果: