Java - CountDownLatch和CyclicBarrier小结

背景

这两JUC类适合放一起比较,随便写写,简单小结。

CountDownLatch

要点:

  • 底层采用AQS队列,源码很简单300行。

使用:

  • 初始化对象并填入(计数器)值,例如:new CountDownLatch(3)。多线程执行完毕时,触发countdown方法将计数器值减1,当值为0时,主线程中被Latch拴住的代码开始执行。

用法一:

public class CountDownLatch_v1 {

    //计数器设为3
    static CountDownLatch latch = new CountDownLatch(3);
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(
                () ->
                {
                    latch.countDown();
                    System.out.println("T1 is OK !");
                }
        );

        Thread t2 = new Thread(
                () ->
                {
                    System.out.println("T2 is OK !");
                    latch.countDown();
                }
        );

        Thread t3 = new Thread(
                () ->
                {
                    System.out.println("T3 is OK !");
                    latch.countDown();
                }
        );

        t1.start();
        t2.start();
        t3.start();
        latch.await(); //main线程阻塞中,等待t1 t2 t3都countDown后,计数器从3变为0后继续运行
        System.out.println("Every T is OK !");
    }
}

用法二:

public class CountDownLatch_v2 {

    static CountDownLatch latch = new CountDownLatch(1);
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(
                () ->
                {
                    try {
                        latch.await();
                        System.out.println("T1 Beginning !");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        );

        Thread t2 = new Thread(
                () ->
                {
                    try {
                        latch.await();
                        System.out.println("T2 Beginning !");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        );

        Thread t3 = new Thread(
                () ->
                {
                    try {
                        latch.await();
                        System.out.println("T3 Beginning !");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        );

        t1.start();
        t2.start();
        t3.start();
        System.out.println("Start !");
        latch.countDown();
    }
}

用法场景:

  1. Main线程等待多个线程T执行完毕后才能执行。多个线程T执行各自的代码段,执行完在线程中执行CountDown方法(减1),减到0后触发Main线程执行。
  2. Main线程等待 T1,T2 两个线程 ,只有两个线程执行达到固定次数(线程内可反复CountDown)后Main线程才能执行。
  3. 为达到最大并行度,Main线程在某一时刻,启动多个线程T。
    PS:new CountDownLatch(1);
    多个T线程中 执行await(); //所有T线程阻塞等待。
    Main线程中执行CountDown //主线程一声令下,多个T线程开始执行。
  4. 情况3和1的结合,多个线程T都干完后,同时开启多个线程M做下一件事。

不足:

  • CountDownLatch 对象New出来后只能使用一次。无法重新赋值反复使用。

CyclicBarrier

要点:

  • 源码不到500,方法不多,采用RE重入锁。
  • 多个线程中通过调用barrier.await相互等待,达到触发点后,触发新线程中自定义方法执行。
  • 精髓在于Cyclic,定义的触发方法可被反复多次触发(前提:CyclicBarrier没有Broken)。

使用:

  • CyclicBarrier构造方法中,指定触发阈值、触发方法(新线程)。达到触发次数时,开启新线程执行触发方法。
  • 子线程中调用barrier.await一次即可(写多次await调用会抛异常),然后就被绊倒了(被阻塞)。

用法一:CyclicBarrier循环多次触发。

public class CyclicBarrier_v2 {

    static CyclicBarrier barrier ;
    public static void main(String[] args) throws InterruptedException {

        barrier = new CyclicBarrier(3,
                () -> {
            System.out.println("Every one is OK !");
        });

        Thread t1 = new Thread(
                () ->
                {
                    try {
                        for(int i=0; i <10; i++) {
                            System.out.println("T1 is OK !");
                            barrier.await();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
        );

        Thread t2 = new Thread(
                () ->
                {
                    try {
                        for(int i=0; i <10; i++) {
                            System.out.println("T2 is OK !");
                            barrier.await();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
        );

        Thread t3 = new Thread(
                () ->
                {
                    try {
                        for(int i=0; i <10; i++) {
                            System.out.println("T3 is OK !");
                            barrier.await();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
        );

        t1.start();
        t2.start();
        t3.start();

    }
}

用法二:二线程交替执行。

public class CyclicBarrier_v3 {

    static CyclicBarrier barrier ;
    public static void main(String[] args) throws InterruptedException {

        barrier = new CyclicBarrier(1,
                () -> {
            System.out.println("A is OK !");
        });

        Thread t1 = new Thread(
                () ->
                {
                    try {
                        for(int i=0; i <10; i++) {
                            System.out.println("T1 is OK !");
                            barrier.await();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
        );
        t1.start();
    }
}

用法场景:

  1. 多个线程执行时需要相互等待,达到等待阈值时,触发新线程执行,可反复触发。
  2. 可实现2个线程交替执行。

注意:

  • 当使用CyclicBarrier做等待(await)的线程被其他线程执行Interrupt方法打断时,会抛出2个异常,InterruptedException和BrokenBarrierException,使栅栏失效。

CountDownLatch 和 CyclicBarrier 区别

  1. CyclicBarrier不会阻塞主线程,CountDownLatch会。
  2. CyclicBarrier会阻塞子线程,CountDownLatch不会。
  3. 由于CountDownLatch的CountDown方法不阻塞,所以CountDownLatch用于等待事件发生(当某个事件发生了可运行CountDown方法,且可多次调用)。而CyclicBarrier用于本线程等待其他线程(所有线程await相互等待,达到阈值后,结束等待,触发新线程)。
  4. CountDownLatch只能用一次,再用就得重新new;CyclicBarrier可以循环使用。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值