JUC辅助类-CountDownLatch,CyclicBarrier和Semaphore学习

参考敖丙,传送门

JUC 辅助类

CountDownLatch

它是一个同步辅助器,允许一个或多个线程一直等待,直到一组在其他线程执行的操作全部完成

它的构造方法,会传入一个 count 值,用于计数

public CountDownLatch(int count) {
	if (count < 0) throw new IllegalArgumentException("count < 0");
	this.sync = new Sync(count);
}

常用的方法有如下两个;

当一个线程调用 await 方法时,就会阻塞当前线程。每当有线程调用一次 countDown 方法时,计数就会减 1,当 count 的值等于 0 的时候,被阻塞的线程才会继续运行

public void await() throws InterruptedException {
	sync.acquireSharedInterruptibly(1);
}
public void countDown() {
	sync.releaseShared(1);
}

示例

当所有人离开教室后才允许关门;

public class CountDownTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 离开教室");
                latch.countDown();
            },i + "").start();
        }
        latch.await();
        System.out.println("教室中所有人已离开,可以锁门");
    }
}

CyclicBarrier

一组线程会互相等待,直到所有线程都到达一个同步点

就像一群人被困到了一个栅栏前面,只有等最后一个人到达之后,他们才可以合力把栅栏(屏障)突破

CyclicBarrier 提供了两种构造方法,如下

第一个构造的参数,指的是需要几个线程一起到达,才可以使所有线程取消等待

第二个构造,额外指定了一个参数,用于在所有线程达到屏障时,优先执行 barrierAction

主要使用的方法就是 await 方法;并且 CyclicBarrier 可以循环利用;

public CyclicBarrier(int parties) {
    this(parties, null);
}
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

示例

现在模拟一个常用的场景,一组运动员比赛 1000 米,只有在所有人都准备完成之后,然后裁判吹口哨之后才可以一起开跑;

public class BarrierTest {
    public static void main(String[] args) {
        //当所有线程到达一个同步点时,就会优先执行该匿名实现类的方法
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4, () -> {
            System.out.println("各就各位,开始!!!");
        });
        Runner r1 = new Runner(cyclicBarrier, "张三");
        Runner r2 = new Runner(cyclicBarrier, "李四");
        Runner r3 = new Runner(cyclicBarrier, "王五");
        Runner r4 = new Runner(cyclicBarrier, "赵六");
        ExecutorService service = Executors.newFixedThreadPool(4);
        service.execute(r1);
        service.execute(r2);
        service.execute(r3);
        service.execute(r4);
        service.shutdown();
    }
}
class Runner implements Runnable {
    private CyclicBarrier barrier;
    private String name;

    public Runner(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }
    @Override
    public void run() {
        try {
            //模拟准备耗时
            Thread.sleep(new Random().nextInt(5000));
            System.out.println(name + ":准备OK");
            //当前线程进入等待
            barrier.await();
            System.out.println(name +": 开跑");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e){
            e.printStackTrace();
        }
    }
}

结果:

张三:准备OK
赵六:准备OK
李四:准备OK
王五:准备OK
各就各位,开始!!!
王五: 开跑
张三: 开跑
赵六: 开跑
李四: 开跑

CountDownLatch 和 CyclicBarrier 区别

  • CountDownLatch 类似是一个计数器,线程完成一个记录一个,计数器递减,只能使用一次
  • CyclicBarrier 的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供 reset 功能,可以多次使用

Semaphore

Semaphore 信号量,用来控制同一时间,资源可被访问的线程数量,一般可用于流量的控制

在信号量上,有定义两种操作,并且 Semaphore 可以控制抢锁是否是公平

  • acquire(获取)当前一个线程调用 acquire 操作时,它要么通过成功获取信号量(信号量减 1 ),要么一直等待下去,直到有线程释放信号量或超时;
  • release(释放)实际上会将信号量的值加 1 ,然后唤醒等待的线程;
public class SemaphoreTest {
    public static void main(String[] args) {
        //公平的抢锁
        Semaphore semaphore = new Semaphore(3,true);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    //当前下称到达后,获取一个信号量,也就是 信号量-1
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t 号车已经抢到车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "\t 号车离开该车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //当前线程执行完毕,那么再次将信号量释放,也即是 信号量+1
                    semaphore.release();
                }
            },"" + i).start();
        }
    }
}

总结

  1. CountDownLatch 是一个线程等待其他线程CyclicBarrier 是多个线程互相等待
  2. CountDownLatch 的计数是减 1 直到 0,CyclicBarrier 是加 1,直到指定值;
  3. CountDownLatch 是一次性的, CyclicBarrier 可以循环利用;
  4. CyclicBarrier 可以在最后一个线程达到屏障之前,选择先执行一个操作;
  5. Semaphore ,需要拿到许可才能执行,并可以选择公平和非公平模式;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值