前言
CyclicBarrier 字面意思是循环栅栏,是一个同步的工具,能够允许一组线程去互相等待直到都到达了屏障,CyclicBarrier对于涉及到固定大小的线程是非常有用的,线程们必须相互等待。该屏障称之为循环屏障,是因为当等待屏障的线程被释放之后,该屏障能循环使用。
什么意思呢?假如有五个探险者去探险,在他们前方有三道门,每道门都需要五个人同时发力召唤神龙才能打开,如果有一个人走的特别快,它先到达了门前,但是它一个人打不开门,需要五个人同时抵达才能打开门,所以走的快的只能等待最慢的达到,一组五个人到齐之后才能执行打开门这个动作。
代码示例
模拟五个人过门的案例
@GetMapping(value = "/cyclicBarrier") public void cyclicBarrier() { // 参与的线程数 int threadNum = 5; //创建cyclicBarrier实例,定义barrierAction CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> System.out.println("已到全部通过栅栏") ); //创建线程开始执行 for (int i = 1; i <= threadNum; i++) { new Thread(() -> { for (int j = 1; j <= 3; j++) { try { Random rand = new Random(); //随机一个2-5的整数 int randomNum = rand.nextInt(4) + 2; Thread.sleep(randomNum * 1000); System.out.println(Thread.currentThread().getName() + ", 通过了第" + j + "道栅栏, " + "使用了 " + randomNum + "s"); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }, "thread--" + i).start(); } }
运行结果:
总结
示意图:
CyclicBarrier是借助ReentrantLock加上Condition 等待唤醒的功能 进而实现的,在构建CyclicBarrier时,传入的值会赋值给CyclicBarrier内部维护count变量,也会赋值给parties变量(这是可以复用的关键)。
每次调用await时,会将count -1 ,操作count值是直接使用ReentrantLock来保证线程安全性。如果count不为0,则添加则condition队列中。如果count等于0时,则把节点从condition队列添加至AQS的队列中进行全部唤醒,并且将parties的值重新赋值为count的值(实现复用)。