同步工具--CyclicBarrier

1. CyclicBarrier 是什么?

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier),它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法。
白话讲CountDownLatch是减法倒计时,CyclicBarrier是加法,比如人员开会,一共有7个人,只有7个人都到了才能开会。

该类用于协调多个线程同步执行操作的场合。

2. 怎么使用 CyclicBarrier

2.1 构造方法

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)

解析:

  • parties 是参与线程的个数
  • 第二个构造方法有一个 Runnable 参数,当屏障被触发时执行的命令。这个Runnable任务在 CyclicBarrier的数目到达后,所有线程被唤醒前执行。

2.2 重要方法

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException

解析:

  • 线程调用 await() 表示自己已经到达了屏障,然后当前线程被阻塞。
  • BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时

2.3 基本使用

使用场景:10个工程师一起来公司应聘,招聘方式分为笔试和面试。首先,要等人到齐后,开始笔试;笔试结束之后,再一起参加面试。把10个人看作10个线程,10个线程之间的同步过程如下图所示:

 

代码实现

public class MyThread extends Thread {

    private CyclicBarrier cyclicBarrier;
    private Random random=new Random();

    @Override
    public void run() {

        try {
            Thread.sleep(random.nextInt(2000));
            System.out.println("线程"+Thread.currentThread().getName()+"已经到达公司");
            cyclicBarrier.await();

            Thread.sleep(random.nextInt(2000));
            System.out.println("线程"+Thread.currentThread().getName()+"已经开始笔试");
            cyclicBarrier.await();

            Thread.sleep(random.nextInt(2000));
            System.out.println("线程"+Thread.currentThread().getName()+"已经面试结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }

    public MyThread(String name,CyclicBarrier cyclicBarrier){
        super(name);
        this.cyclicBarrier=cyclicBarrier;
    }
    
}

 

public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getName()+"到达,一起开始-------");
            }
        });
        for (int i = 0; i <5 ; i++) {
            MyThread myThread = new MyThread("线程"+i,cyclicBarrier);
            myThread.start();
        }
    }

打印结果:

线程线程3已经到达公司
线程线程1已经到达公司
线程线程4已经到达公司
线程线程0已经到达公司
线程线程2已经到达公司
线程2到达,一起开始-------
线程线程4已经开始笔试
线程线程2已经开始笔试
线程线程3已经开始笔试
线程线程0已经开始笔试
线程线程1已经开始笔试
线程1到达,一起开始-------
线程线程1已经面试结束
线程线程0已经面试结束
线程线程2已经面试结束
线程线程4已经面试结束
线程线程3已经面试结束

3. CyclicBarrier 使用场景

可以用于多线程计算数据,最后合并计算结果的场景。

public class TestCyc2 {

    public static void main(String[] args) {

        final ConcurrentHashMap<String,Integer> map=new ConcurrentHashMap<String,Integer>();

        FutureTask futerTask=new FutureTask<Integer>(new Callable<Integer>() {
            public Integer call() throws Exception {
                Integer count=0;
                Set<Map.Entry<String, Integer>> entries = map.entrySet();
                for (Map.Entry<String,Integer> e :entries){
                    String key = e.getKey();
                   int value = e.getValue();
                    System.out.println("key:"+key+","+"value:"+value);
                    count+=value;
                }
                System.out.println("call方法 count"+count);
                return count;
            }
        });

        final CyclicBarrier barrier=new CyclicBarrier(5,futerTask );

        for(int i=0;i<5;i++){
            final int k=i;
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(3000);
                        map.put(Thread.currentThread().getName(),k);
                        barrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }


        try {
            Integer integer = (Integer) futerTask.get();
            System.out.println("最后结果="+integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }


}

 

打印结果:

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值