多线程工具-CountDownLatch、CyclicBarrier、Semaphore


1.CountDownLatch

A synchronization aid that allows one or more threads to wait until a set of 
operations being performed in other threads completes.

CountDownLatch是一个辅助线程同步的工具,允许一个或多个线程等待其他线程执行完成。但是只能使用一次,不能重置。

1.1 核心方法

构造函数CountDownLatch(int count)

the number of times {@link #countDown} must be invoked before threads can pass through {@link #await}

传入的count数,通俗的讲就是需要主线程等待其他线程执行完成的线程个数,即主线程需要等待多少个线程执行完成,实际count充当的是一个计数器的作用。

await()

见名知意,该方法会阻塞当前线程,直到count清零为止。

countDown()

计数器 count 减一,当 count 为零时,解除所有阻塞的线程。

await(long timeout, TimeUnit unit)

该方法多一个超时时间参数,过了超时时间不管计数器count有没有清零,所有阻塞线程都会解除阻塞继续往下执行。可以防止线程由于意外导致中断没有调用到countDown()方法,导致阻塞线程一直处于阻塞等待状态

1.2 示例

比如一个大人照顾三个孩子吃饭,大人需要照顾三个孩子吃完饭了之后才能开始吃饭。
    public static void main(String[] args) throws InterruptedException {
        int count = 3;
        CountDownLatch latch = new CountDownLatch(count);
        System.out.println("==> 饭来了~");
        for (int i = 0; i < count; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "==> 吃完饭了");
                }finally {
                    //子线程执行完成,清除计数器
                    latch.countDown();
                }
            },"孩子"+ i).start();
        }
        //主线程等待其他线程执行完成
        latch.await();
        System.out.println("==> 大人开始吃饭");
    }

执行结果

==> 饭来了~
孩子0 ==> 吃完饭了
孩子2 ==> 吃完饭了
孩子1 ==> 吃完饭了
==> 大人开始吃饭

2、CyclicBarrier

一组线程之间相互等待,直到所有线程都达到阻塞点await之后,才往下执行。

2.1 核心方法

构造函数1 – CyclicBarrier(int parties)

parties 相互之间等待的线程数

构造函数2 – CyclicBarrier(int parties, Runnable barrierAction)

barrierAction 所有线程达到阻塞点,解除阻塞时的回调

await()

阻塞点,所有线程都达到该阻塞点之后,才能继续往下执行。

await(long timeout, TimeUnit unit)

带有超时时间的阻塞点。如果超过时间过了,但是还有线程未达到阻塞点则会抛出TimeoutException异常,其他等待线程则抛出BrokenBarrierException异常

2.2 示例

一个大人和3个小孩一起吃饭,只有他们都吃完了之后才能吃水果
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        int count = 3;
        final CyclicBarrier barrier = new CyclicBarrier(4, () -> {
            System.out.println("都吃完饭了,开始发水果 ~ ");
        });
        System.out.println("开饭咯~");
        for (int i = 0; i < count; i++) {
            final int time = i;
            new Thread(() -> {
                String childName = Thread.currentThread().getName();
                try {
                    System.out.println(childName + " ==> 开始吃饭");
                    TimeUnit.SECONDS.sleep(time);//吃饭耗时
                    System.out.println(childName + " ==> 吃完饭了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //子线程执行完成,调用清除计数器
                    try {
                        barrier.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(childName + " ==> 开始吃水果");
            }, "孩子" + i).start();
        }
        System.out.println("大人 ==>  开始吃饭");
        TimeUnit.SECONDS.sleep(0);//吃饭耗时
        System.out.println("大人 ==> 吃完饭了");
        barrier.await();
        System.out.println("大人 ==> 开始吃水果");
    }

执行结果


开饭咯~
大人 ==>  开始吃饭
孩子0 ==> 开始吃饭
孩子2 ==> 开始吃饭
孩子1 ==> 开始吃饭
孩子0 ==> 吃完饭了
大人 ==> 吃完饭了
孩子1 ==> 吃完饭了
孩子2 ==> 吃完饭了
都吃完饭了,开始发水果 ~ 
孩子2 ==> 开始吃水果
孩子0 ==> 开始吃水果
孩子1 ==> 开始吃水果
大人 ==> 开始吃水果


3、Semaphore

对一组线程,允许同时执行的线程数,类似限流器的作用,只有获取到Semaphore的许可后才能执行。

3.1 核心方法

构造函数 Semaphore(int permits)

permits许可证的数量,即允许同时执行的线程数量。

acquire()

获取许可证。如果Semaphore中的许可证已用完,则当前线程会一直处于阻塞状态,直到有可有的许可证出现为止。

release()

释放(交还)许可证。

3.3 示例

5个孩子游玩游戏屋,游戏屋同一时间只能供2人游玩。只有从老师手里拿到了凭证才能进去游玩。
    public static void main(String[] args) {
        List<Thread> children = new ArrayList<>();
        Semaphore semaphore = new Semaphore(2);
        for (int i = 0; i < 5; i++) {
            children.add(new Thread(() -> {
                String name = Thread.currentThread().getName();
                try {
                    // 找老师获取凭证
                    semaphore.acquire();
                    System.out.println(String.format("%s ==>  拿到凭证,进去游玩", name));
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(String.format("%s ==> 出门,交还凭证 !", name));
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "child-" + i));
        }
        children.forEach(Thread::start);
    }

执行结果

child-1 ==>  拿到凭证,进去游玩
child-0 ==>  拿到凭证,进去游玩
child-0 ==> 出门,交还凭证 !
child-1 ==> 出门,交还凭证 !
child-2 ==>  拿到凭证,进去游玩
child-3 ==>  拿到凭证,进去游玩
child-3 ==> 出门,交还凭证 !
child-2 ==> 出门,交还凭证 !
child-4 ==>  拿到凭证,进去游玩
child-4 ==> 出门,交还凭证 !
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值