天天看点

辅助类CountDownLatch, CyclicBarrier, SemaphoreCountDownLatch 减少计数CyclicBarrier 循环屏障Semaphore 信号量

文章目录

  • CountDownLatch 减少计数
    • 场景
  • CyclicBarrier 循环屏障
    • 场景
  • Semaphore 信号量
    • 场景

JUC 中提供了三种常用的辅助类, 通过这些辅助类可以很好的解决线程数量过多时 Lock 锁的频繁操作

CountDownLatch 减少计数

  • CountDownLatch 类可以设置一个计数器, 然后通过 countDown 方法来进行减1 的操作
  • 使用await() 方法等待计数器为0, 然后继续执行 await() 方法之后的语句
  • 当一个或多个线程调用 await() 方法时, 这些线程会阻塞
  • 其他线程调用 countDown 方法会将计数器减1(调用 countDown 方法的线程不会阻塞)
  • 当计数器的值变为 0 时, 因 await() 方法阻塞的线程会被唤醒, 继续执行

场景

6个同学陆续离开教室后班长才可以关门

public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 6; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+ "同学离开教室");
                    countDownLatch.countDown();
                }
            },String.valueOf(i)).start();
        }

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("班长锁门啦!!!");
    }
           

CyclicBarrier 循环屏障

CyclicBarrier 的构造方法的第一个参数是目标障碍数, 每次执行 CyclicBarrier.await() 方法, 障碍数就会加1

如果达到了目标障碍数, 就执行给定的屏障动作, 由最后一个进入屏障的线程执行

场景

6个同学陆续离开教室后班长才可以关门

public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, new Runnable() {
            @Override
            public void run() {
                System.out.println("班长锁门啦!");
            }
        });

        for (int i = 0; i < 4; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 同学离开教室了");
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            },String.valueOf(i)).start();
        }
    }
           

Semaphore 信号量

  • Semaphore 的构造方法中传入的第一个参数是最大信号量(可以看成是最大线程池)
  • 每个信号量只能分发一个许可证
  • 使用 acquire() 方法获得许可证, 使用 release() 方法释放许可证

场景

抢车位, 6辆汽车, 3个停车位

public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 6; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + " 抢到了停车位");
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + " --------释放了停车位");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        semaphore.release();
                    }
                }
            },String.valueOf(i)).start();
        }
    }