CyclicBarrier 公共屏障点
来源:互联网 发布:嘉兴兼职淘宝美工 编辑:程序博客网 时间:2024/05/17 03:32
在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等待其他线程都完成某一阶段后再执行,等所有线程都到达某一个阶段后再统一执行。
JDK:
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
对于失败的同步尝试,CyclicBarrier 使用了一种快速失败的、要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么其他所有线程(甚至是那些尚未从以前的 await() 中恢复的线程)也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。
JDK地址:
http://www.cjsdn.net/doc/jdk50/java/util/concurrent/CyclicBarrier.html#CyclicBarrier(int, java.lang.Runnable)
//构造方法摘要CyclicBarrier(int parties) //创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作。CyclicBarrier(int parties, Runnable barrierAction) //创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
Example1:
package tags;import java.util.Random;import java.util.concurrent.CyclicBarrier;/** * CyclicBarrier调用CyclicBarrier.await()进入等待的线程数, * 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 * CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 * CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。 */public class CyclicBarrierTest { public static class ComponentThread implements Runnable { CyclicBarrier barrier;// 计数器 int ID; // 组件标识 int[] array; // 数据数组 // 构造方法 public ComponentThread(CyclicBarrier barrier, int[] array, int ID) { this.barrier = barrier; this.ID = ID; this.array = array; } public void run() { try { array[ID] = new Random().nextInt(100); System.out.println("Component " + ID + " generates: " + array[ID]); System.out.println("Component " + ID + " sleep"); // 在这里等待Barrier处 barrier.await(); System.out.println("Component " + ID + " awaked"); // 计算数据数组中的当前值和后续值 int result = array[ID] + array[ID + 1]; System.out.println("Component " + ID + " result: " + result); } catch (Exception ex) { } } } /** * 测试CyclicBarrier的用法 */ public static void testCyclicBarrier() { final int[] array = new int[3]; CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() { // 在所有线程都到达Barrier时执行 public void run() { System.out.println("testCyclicBarrier run"); array[2] = array[0] + array[1]; } }); // 启动线程 new Thread(new ComponentThread(barrier, array, 0)).start(); new Thread(new ComponentThread(barrier, array, 1)).start(); } public static void main(String[] args) { CyclicBarrierTest.testCyclicBarrier(); }}
结果:
Component 1 generates: 40
Component 0 generates: 8
Component 1 sleep
Component 0 sleep
testCyclicBarrier run
Component 0 awaked
Component 0 result: 48
Component 1 awaked
Component 1 result: 88
两个线程分别执行,互不影响 ,执行到barrier.await();时该线程进入等待状态,
当两个线程都执行到barrier.await();时,达到CyclicBarrier启动所需的阻塞线程数,进入到new CyclicBarrier(2, new Runnable()...)里面的方法, 执行完里面的方法后,等待的两个线程再次被唤醒,继续各自执行线程后面的语句。
Example2:
比如有几个旅行团需要途经深圳、广州、韶关、长沙最后到达武汉。旅行团中有自驾游的,有徒步的,有乘坐旅游大巴的;这些旅行团同时出发,并且每到一个目的地,都要等待其他旅行团到达此地后再同时出发,直到都到达终点站武汉。
这时候CyclicBarrier就可以派上用场。CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。
package tags;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestCyclicBarrier {// 徒步需要的时间: Shenzhen, Guangzhou, Shaoguanprivate static int[] timeWalk = { 5, 8, 15};// 自驾游private static int[] timeSelf = { 1, 3, 4};// 旅游大巴private static int[] timeBus = { 2, 4, 6};static String now() {SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");return sdf.format(new Date()) + ": ";}static class Tour implements Runnable {private int[] times;private CyclicBarrier barrier;private String tourName;public Tour(CyclicBarrier barrier, String tourName, int[] times) {this.times = times;this.tourName = tourName;this.barrier = barrier;}public void run() {try {Thread.sleep(times[0] * 1000); //使用 times岔开各组时间,使其显示不同的now()System.out.println(now() + tourName + " Reached Shenzhen");barrier.await();Thread.sleep(times[1] * 1000);System.out.println(now() + tourName + " Reached Guangzhou");barrier.await();Thread.sleep(times[2] * 1000);System.out.println(now() + tourName + " Reached Shaoguan");} catch (InterruptedException e) {} catch (BrokenBarrierException e) {}}}public static void main(String[] args) {// 三个旅行团CyclicBarrier barrier = new CyclicBarrier(3);ExecutorService exec = Executors.newFixedThreadPool(3);exec.submit(new Tour(barrier, "WalkTour", timeWalk));exec.submit(new Tour(barrier, "SelfTour", timeSelf));exec.submit(new Tour(barrier, "BusTour", timeBus));exec.shutdown();}}
结果:
15:13:11: SelfTour Reached Shenzhen
15:13:12: BusTour Reached Shenzhen
15:13:15: WalkTour Reached Shenzhen
15:13:18: SelfTour Reached Guangzhou
15:13:19: BusTour Reached Guangzhou
15:13:23: WalkTour Reached Guangzhou
15:13:27: SelfTour Reached Shaoguan
15:13:29: BusTour Reached Shaoguan
15:13:38: WalkTour Reached Shaoguan
例子来源:http://conkeyn.iteye.com/blog/546280(测试时稍有修改)
源码分析:
private final ReentrantLock lock = new ReentrantLock(); private final Condition trip = lock.newCondition(); /** 达到的数量 */ private final int parties; /* 数量满足后执行的线程 */ private final Runnable barrierCommand; /** The current generation */ private Generation generation = new Generation();private static class Generation { boolean broken = false; }public CyclicBarrier(int parties) { this(parties, null); }public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; }
public int await() throws InterruptedException, BrokenBarrierException { try { return dowait(false, 0L); } catch (TimeoutException toe) { throw new Error(toe); // cannot happen; } }private int dowait(boolean timed, long nanos) throws InterruptedException,BrokenBarrierException,TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation; if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } int index = --count; if (index == 0) { // index为0时,线程数量达到屏障数量,执行barrierCommand,并唤醒所有线程 boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out for (;;) { try { if (!timed)//若未达到屏障数量,每一个线程进入时都阻塞在这//此时会释放锁,以便下一线程进入trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch(InterruptedException ie) { if (g == generation && !g.broken) { breakBarrier(); throw ie; } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.currentThread().interrupt(); } } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); }}
/** * Sets current barrier generation as broken and wakes up everyone. * Called only while holding lock. */ private void breakBarrier() { generation.broken = true;count = parties; trip.signalAll(); }private void nextGeneration() { // 唤醒所有线程 trip.signalAll(); // set up next generation// 重置屏障数量,使其可循环使用 count = parties; generation = new Generation(); }
其实就是使用一个重入锁,一个Condition实现。
- CyclicBarrier 公共屏障点
- CyclicBarrier 公共屏障点
- CyclicBarrier公共屏障点:一个同步辅助类,它允许一组线程互相等待
- Java多线程与并发库高级应用之公共屏障点CyclicBarrier
- java CyclicBarrier (栅栏) 作用是使 指定个数的请求线程互相等待, 拦截在某个公共屏障点(就是栅栏外面)然后全到齐了一起访问这个屏障点的内容
- 同步屏障CyclicBarrier
- 同步屏障CyclicBarrier
- 同步屏障CyclicBarrier
- 并发编程--CyclicBarrier屏障
- 同步屏障CyclicBarrier
- 同步屏障CyclicBarrier
- 并发编程之屏障CyclicBarrier
- 并发编程之屏障CyclicBarrier
- Java多线程--同步屏障CyclicBarrier
- Java的CyclicBarrier(循环屏障)
- java.util.concurrent中:同步屏障CyclicBarrier
- Java多线程/并发23、循环屏障CyclicBarrier
- 并发工具类:同步屏障CyclicBarrier
- 还有人开发工作流吗?还有使用JBPM进行开发的吗?
- 使用CompletionService获取多线程返回值
- Java注解annotation用法和自定义注解处理器
- px,em,rem,vh,vw,vmin,vmax的区别及浏览器支持
- javascript 操作select
- CyclicBarrier 公共屏障点
- 软件安装
- hibernate 不同查询方法实例
- Semaphore 并发个数控制
- js 回调函数理解总结
- java 路径 批处理空格 getRuntime().exec 空格解决办法
- pads中pcb文件怎么转换为低版本
- CountDownLatch
- 设计模式学习笔记——外观(Facade)模式