JAVA多线程(十三)Java多线程之CyclicBarrier

那年仲夏 提交于 2020-01-16 04:15:56

1.JAVA多线程(十三)Java多线程之CyclicBarrier

   CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。

1.1 CyclicBarrier类

   CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。

  • CyclicBarrier是一种同步机制,它可以使得一组线程在同一个障碍点进行等待。
  • CyclicBarriers 可以通过重置计数器从而重新使用。
  • CyclicBarrier支持一个可选的Runnable命令(实例化构造函数中的参数),该命令在最后一个线程到达后,但在任何线程被释放之前被执行。这一命令在barrier处只会被执行一次,且由最后到达的线程完成。这种屏障行为对于在任何一方继续之前更新共享状态都很有用。
  • all-or-none破损模型:如果一个线程因为中断(or执行过程的失败,超时等)过早的离开了barrier点,那么等待在barrier点的其他所有线程也会在同一时间因为BrokenBarrierException或者InterruptedException异常而离开barrier。
    内存一致性影响:
    1. 线程在调用await()方法之前的行为要优先于barrier action中的任何行为。
    1. barrier action成功返回这一行为要优先于所有其他等待线程await()后的行为。

1.2 CyclicBarrier示例

package com.yuanxw.chapter13;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

/**
 * CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。
 * 它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
 * CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
 */
public class CyclicBarrierExample {

    private static volatile boolean isRunning = true;
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                isRunning = false;
                System.out.println("任务执行结束后,回调函数!!!");
            }
        });

        /** 线程-A **/
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(20);
                System.out.println(String.format("线程【%s】执行完成", Thread.currentThread().getName()));
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        },"Thread-A").start();

        /** 线程-A **/
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(10);
                System.out.println(String.format("线程【%s】执行完成", Thread.currentThread().getName()));
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        },"Thread-B").start();

        while (isRunning) {
            System.out.println(String.format("当前正在等待数量:【%s】", cyclicBarrier.getNumberWaiting()));
            System.out.println(String.format("正在等待所需数量:【%s】 ", cyclicBarrier.getParties()));
            System.out.println(String.format("中断或超时:【%s】", cyclicBarrier.isBroken()));
            TimeUnit.SECONDS.sleep(5);
        }
    }
}

执行结果:

当前正在等待数量:【0】
正在等待所需数量:【2】 
中断或超时:【false】
当前正在等待数量:【0】
正在等待所需数量:【2】 
中断或超时:【false】
线程【Thread-B】执行完成
当前正在等待数量:【1】
正在等待所需数量:【2】 
中断或超时:【false】
当前正在等待数量:【1】
正在等待所需数量:【2】 
中断或超时:【false】
线程【Thread-A】执行完成
任务执行结束后,回调函数!!!

1.3 CyclicBarrier 和 CountDownLatch 的区别

  1. CountDownLatch 是计数器,只能使用一次,而 CyclicBarrier 的计数器提供 reset 功能,可以多次使用。
  2. 对于 CountDownLatch 来说,重点是“一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待。而对于 CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待。
  3. CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而 CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。

    – 以上为《JAVA多线程(十三)Java多线程之CyclicBarrier》,如有不当之处请指出,我后续逐步完善更正,大家共同提高。谢谢大家对我的关注。

——厚积薄发(yuanxw)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!