Java 并发:CyclicBarrier 实现线程协作控制
背景
电脑桌面上有一张“Java 并发编程知识思维导图”,这两天刚好又用到了 CyclicBarrier 类,趁着周末整理下 CyclicBarrier 的用法。
Java 并发知识思维导图
(此图来源于网络,原文链接不详,如有侵权,请私信联系本人删除)
CyclicBarrier 位于图中协作类的范畴,JKD 官方文档中对它的解释是这样的:
synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other.
适用于一组线程需要等待其他所有线程都到达某个点的场景。
Barrier ,是障碍物、栅栏之意,线程一旦调用它的 await 方法后就处于被阻拦状态,直到所有线程都执行过 await 后,线程的阻塞状态才解除。Cyclic ,是循环的意思,是指当所有线程都解除阻塞状态后,它还可以被重复使用。
基本用法
CyclicBarrier 的构造方法包含两个参数:
public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; }
parties:等待在栅栏上的线程总数;
barrierAction:当所有线程都达到栅栏后需要执行的动作,JVM 会开启一个新线程执行该任务。
实践编码
模拟一种集体出游的行动过程,每个参与者都先按自己的情况安排事情,然后到集合点集合;等待所有参与者都达到集合地点乘坐旅游大巴到达出游地,下车后再自由行动。这里就涉及的等待其他人都达到的场景,就可以用 CyclicBarrier 实现。
这里定义一个游客类 VisitorTask:
import java.util.concurrent.CyclicBarrier; public class VisitorTask implements Runnable{ private CyclicBarrier barrier; private boolean isSleep; private VisitorTask(CyclicBarrier barrier,boolean isSleep) { this.barrier = barrier; this.isSleep = isSleep; } @Override public void run() { //先执行自己的事情 System.out.println(Thread.currentThread().getName()+"进行出游准备。"); System.out.println(Thread.currentThread().getName()+"到达集合点。"); if(isSleep) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //等待其他线程都到达该栅栏 try { barrier.await(); } catch (Exception e) { e.printStackTrace(); } //再执行其他事情 System.out.println(Thread.currentThread().getName()+"自由观光。"); } }
接着编写控制类,启动 N 个任务,并开启一个栅栏对象:
public static void main(String[] args) { int count= 5; final ScheduledExecutorService service = Executors.newScheduledThreadPool(count); // 线程协作类:等待所有任务都执行完成后,主线程则执行收尾工作 CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() { @Override public void run() { // 关闭线程池 service.shutdown(); // 统计操作总耗时 System.out.println(Thread.currentThread().getName() + " all visitor are here"); } }); //开启N个线程,偶数线程执行 await之前休眠 for(int i=0;i<count;i++) { service.submit(new VisitorTask(barrier,i%2==0)); } }
运行结果:
pool-1-thread-1进行出游准备。
pool-1-thread-4进行出游准备。
pool-1-thread-3进行出游准备。
pool-1-thread-3到达集合点。
pool-1-thread-2进行出游准备。
pool-1-thread-4到达集合点。
pool-1-thread-1到达集合点。
pool-1-thread-2到达集合点。
pool-1-thread-5进行出游准备。
pool-1-thread-5到达集合点。
pool-1-thread-5 all visitor are here
pool-1-thread-5自由观光。
pool-1-thread-4自由观光。
pool-1-thread-1自由观光。
pool-1-thread-3自由观光。
pool-1-thread-2自由观光。
从运行结果来看:在所有线程都调用 await 之前,已经达到的线程都是被阻拦状态的,当所有线程都调用过 await 后 barrier.await() == 0 为真,JVM 开启一个新线程执行 Barrier 的回调任务,然后所有线程继续 await 后面的操作。
编程启示录
再总结下前文的思维导图:
- 分工:高效的拆解任务分给线程
- 协作:线程之间的协作控制
- 互斥:保证同一时刻只允许一个线程访问共享资源
这是 Java 并发编程的主要内容,并发包里面的工具类的用法并不复杂,尝试着多用用,并发编程其实还是孰能生巧的事情!
- Java线程(十):CyclicBarrier-用路障实现分阶段线程并发
- 下一次面试就问,Java并发工具CyclicBarrier的用法及实现原理
- 使用java并发工具栅栏(CyclicBarrier)实现多线程等待,同一时刻执行共同任务
- Java并发编程中级篇(四):使用CyclicBarrier实现并发线程在集合点同步
- java 1.5 并发流程控制CountDownLatch,CyclicBarrier,Semaphore
- Java线程(十):CyclicBarrier-用路障实现分阶段线程并发
- Java并发编程:Condition实现线程间协作
- java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)
- Java_并发线程_Semaphore、CountDownLatch、CyclicBarrier、Exchanger
- java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)
- Java高并发程序-Chapter3 JDK并发包(第十五讲)同步控制之CyclicBarrier 循环栅栏
- Java_并发线程_Semaphore、CountDownLatch、CyclicBarrier、Exchanger
- Java线程:并发协作-生产者消费者模型
- 黑马程序员-Condition条件对象、Semaphore、CyclicBarrier、倒计时门栓 CountDownLatch、Exchanger(实现两个线程之间数据交换
- 线程高级应用-心得5-java5线程并发库中Lock和Condition实现线程同步通讯
- Java线程:并发协作-生产者消费者模型
- Java线程:并发协作-死锁
- java并发实现用户级线程
- Java:使用wait()与notify()实现线程间协作
- Java:使用wait()与notify()实现线程间协作