【JDK源码分析】通过源码分析CyclicBarrier
2018-07-25 13:05:48来源:博客园 阅读 ()
前言
CyclicBarrier它是什么?一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。类似于朋友之间联系要在中午聚个会,几个朋友全部到齐后才开始喝酒吃菜。
源码
CyclicBarrier属性和构造器
public class CyclicBarrier { // 互斥锁 private final ReentrantLock lock = new ReentrantLock(); // 条件等待 private final Condition trip = lock.newCondition(); // 参与者数目 private final int parties; // 栅栏放开时的执行任务 private final Runnable barrierCommand; // 用于表示栅栏是否放开或者重置 private Generation generation = new Generation(); // 在等待的参数者数目 private int count; // 构造parties个参与者的栅栏 public CyclicBarrier(int parties) { this(parties, null); } // 构造parties个参与者的栅栏,并且设置栅栏放开时要执行的任务 public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; } }
CyclicBarrier方法
1. await方法
在所有参与者都已经在此 栅栏上调用 await 方法之前或者超时,会一直等待
public public int int await() await() throws InterruptedException, BrokenBarrierException { throws InterruptedException, BrokenBar try { return dowait(false, 0L); } catch (TimeoutException toe) { throw new Error(toe); // cannot happen } } // 设置超时 public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException { return dowait(true, unit.toNanos(timeout)); } 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(); } // 每调用一次await减少一次count数 int index = --count; if (index == 0) { // tripped // 所有参与者已到达栅栏位置 // 初始化执行任务状态,可见构造器设置的执行任务是由最后一个到达栅栏位置的线程来执行的 boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; // 重置栅栏并唤醒所有线程 nextGeneration(); return 0; } finally { if (!ranAction) // command执行出错 // 任务执行出错将栅栏状态设置成损坏、重置剩余等待线程数以及唤醒等待的线程 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(); } }
breakBarrier方法调用的signalAll,以及dowait方法中trip.await、trip.awaitNanos在本人这篇【JDK源码分析】通过源码深入分析AbstractQueuedSynchronizer博客有分析,此处不再赘述。
// 将栅栏状态设置成损坏、重置剩余等待线程数以及唤醒等待的线程 private void breakBarrier() { generation.broken = true; count = parties; // 唤醒所有线程 trip.signalAll(); } // 重置栅栏,下次还可以再使用 private void nextGeneration() { // 唤醒所有线程 trip.signalAll(); count = parties; generation = new Generation(); }
2. reset方法
将栅栏重置为其初始状态并开启一个新的栅栏
public void reset() { final ReentrantLock lock = this.lock; lock.lock(); try { breakBarrier(); // break the current generation nextGeneration(); // start a new generation } finally { lock.unlock(); } }
CyclicBarrier的源码分析到此结束
用法
如下面,张锅和张嫂约起去火锅店吃火锅,二个人到齐后才叫老板上菜,下面上示例:
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> System.out.println(Thread.currentThread().getName() + "喊:老板,我们人到齐了,把菜上起!")); new Thread(() ->{ System.out.println("张锅在去火锅店的路上..."); try { Thread.sleep(System.currentTimeMillis() % 1000); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, "张锅").start(); new Thread(() ->{ System.out.println("张嫂在去火锅店的路上..."); try { Thread.sleep(System.currentTimeMillis() % 1000); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, "张嫂").start();
打印结果
张锅在去火锅店的路上...
张嫂在去火锅店的路上...
张锅喊:老板,我们人到齐了,把菜上起!
总结
当遇到多条线程需要相互等待时,使用CyclicBarrier工具是一个比较好的选择。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- jdk各个版本下载 2020-06-11
- 你说研究过Spring里面的源码,循环依赖你会么? 2020-06-09
- 通俗理解spring源码(六)—— 默认标签(import、alias、be 2020-06-07
- 数据结构:用实例分析ArrayList与LinkedList的读写性能 2020-06-04
- JDK8的JVM内存模型小结 2020-06-03
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash