Skip to content

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("关闭大门");
}

运行结果:
Alt text

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();
    }
}

运行结果:
Alt text

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();
    }
}

运行结果:
Alt text