java多线程之JUC包下CyclicBarrier的使用

1.CyclicBarrier的思想


CyclicBarrier的思想在我们生活中就可以找到,我们就以火车道口拦杆为例:

我们先看一下,没有火车道口拦杆时的情形:


没有拦杆时,人们随意穿行

但是,正如一句老话说的好,没有约束的自由总是危险的。

想象一下,这时候,火车突然来了。。。


火车疾驰而来


这时候,恐怕就出现了这种场景,一场人间生死离别的惨祸


行人不幸被撞

有约束的自由才是真正的自由:



有约束才更安全

我们知道火车道口拦杆的作用:为了让行人规避火车,在火车运行的时候,铁路人员把拦杆放下,这样所有的行人都不能通过了。只有到拦杆处聚集了一拨人的时候,才会统一把拦杆打开,让所有人一次通过。而之后来的人,只有等到下一次拦杆打开才能通过。并且,等待在同一个拦杆处的人,不管你来的是早是晚,你都要先等待。只有等拦杆打开之后,你们这一组人才能同时通过。并不是说,谁先来谁先通过。我们通过这个拦杆可以控制让一批人同时通过。


CyclicBarrier就类似于一个火车道口拦杆。我们想通过CyclicBarrier来实现一个同步控制,可以把每一个cyclicBarrier理解成一个火车道口拦杆。


2.CyclicBarrier的作用

而JUC包下的cyclicBarrier的作用也是这样,它同样实现的也是一个同步控制。它可以对一组线程进行协同。同一个CyclicBarrier下的所有线程一旦到达了拦杆处,它就必须等待,只有等到所有线程都到达了公共屏障点处,才能继续运行。

CyclicBarrier是一个同步辅助器。 通俗点讲就是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。



3.CyclicBarrier的理解

我们可以看到CyclicBarrier的内部是使用重入锁ReentrantLock和Condition。它有两个构造函数:

CyclicBarrier(int parties):创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。

CyclicBarrier(int parties, Runnable barrierAction) :创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行                                                                                    给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。


parties表示拦截线程的数量,这里的parties就是起到一个计数器的作用。parties规定了到达屏障处的线程个数。只有当规定数量的线程都到达了公共屏障点时,才会放行。

关键点


理解CyclicBarrier的关键是要理解: await()方法 和parties 构造参数。

parties参数就是一个倒计时计数器,它被初始化为一个值N,只有N的值为减为0时即:所有的线程都达到了公共屏障点时,才会放行所有等待在拦杆处线程,让它们能继续往下运行。

而每当有一个线程调用await()方法就意味着有一个线程到达了公共屏障点cyclicBarrier。这时,parties的值减1。




4.代码案例


需求: 只有当三个线程都同时到达拦杆处时,才放行。


下面这个小案例就简单说明了CyclicBarrier的使用。


demo截图截图


最后,贴上完整的代码:

public class CyclicBarrierTest {

private static CyclicBarrier  cyclicBarrier;

/**

* 问题:cyclicBarrier的await方法的作用是什么???

*      在什么时候调用yclicBarrier.await()方法

*        cyclicBarrier = new CyclicBarrier(5, new Runnable());

*        构造方法中的5的作用,cyclicBarrier的实现逻辑是不是就是5和await的结合实现。

*       

* @param args

*/

//关键点: 有一个线程调用await()方法就意味着有一个线程到达了cyclicBarrier

//关键词: 公共屏障点 commont barrier point

    //CyclicBarrier的两个构造函数


  //parties表示拦截线程的数量。

  //CyclicBarrier(int parties)

  //当所有线程都已经到达barrier处(index == 0),

//则会通过nextGeneration()进行更新换地操作,在这个步骤中,做了三件事:唤醒所有线程,重置count,generation。

//这里面的parties就是起到一个计数器的作用

static class CyclicBarrierThread extends Thread{

        public void run() {

            //System.out.println(Thread.currentThread().getName() + "到了");

            //等待

            try {

            //执行一些其他逻辑

            //do  something before reaching barrier

            System.out.println(Thread.currentThread().getName()+"正在来的路上");

            System.out.println(Thread.currentThread().getName()+"到达了拦杆处");

                cyclicBarrier.await();

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

public static void main(String[] args) {

//只有3个人都到齐时,才开会

//人都到齐之后,执行Runnable中的动作

cyclicBarrier=new CyclicBarrier(3, new Runnable() {

@Override

public void run() {

System.out.println("所有线程都已到达拦杆处,现在把拦杆打开了,大家都通过吧");

}

});

//开启3个线程

for (int i = 0; i < 3; i++) {

//创建3个线程

Thread t=new CyclicBarrierThread();

t.setName("线程Thread_"+i);

t.start();

}

}

}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容