线程屏障CyclicBarrier实现原理
2019-02-17 01:52:07来源:博客园 阅读 ()
生产环境中,存在需要等待多个线程都达到某种状态后,才继续运行的情景。并发工具CyclicBarrier就能够完成这种功能。本篇从源码方面,简要分析CyclicBarrier的实现原理。
使用示例
public class CyclicBarrierTest { public static void main(String[] args) { //屏障,阻拦3个线程 CyclicBarrier cyclicBarrier = new CyclicBarrier(3); new Thread(new Runnable() { @Override public void run() { System.out.println("线程1正在执行"); try { // 等待 cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("线程1运行结束,时间: " + System.currentTimeMillis()); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println("线程2正在执行"); try { // 等待 cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("线程2运行结束,时间: " + System.currentTimeMillis()); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println("线程3正在执行"); try { //线程3阻塞2秒,测试效果 Thread.sleep(2000); // 等待 cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("线程3运行结束,时间: " + System.currentTimeMillis()); } }).start(); } }
执行结果如下:
线程1正在执行 线程2正在执行 线程3正在执行 线程1运行结束,时间: 1550324116837 线程3运行结束,时间: 1550324116837 线程2运行结束,时间: 1550324116837
可以看到线程1,2,3在同一个时间结束。
源码分析
主要成员:
private final ReentrantLock lock = new ReentrantLock(); private final Condition trip = lock.newCondition(); private int count;
CyclicBarrier主要借助重入锁ReentrantLock和Condition实现。count初始值等于CyclicBarrier实例化指明的等待线程数量,用于等待线程计数。
主要方法await()
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(); // 1 try { final Generation g = generation; if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } int index = --count; // 2 if (index == 0) { // 3 boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); // 4 return 0; } finally { if (!ranAction) breakBarrier(); // 5 } } // loop until tripped, broken, interrupted, or timed out for (;;) { try { if (!timed) trip.await(); // 6 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(); // 7 } }
- 对当前对象加锁
- 每个线程获得锁,执行这部分代码时,都把count - 1,记做index
- 如果index为0,执行第4步,代表CyclicBarrier屏障已经拦截了足够数量(count)的线程,线程可以接着往下执行了。不为0,说明当前线程还没有达到屏障CyclicBarrier拦截的数量,执行第6步
- 调用nextGeneration()方法,唤醒所有等待线程
- breakBarrier()确保一定能执行唤醒动作
- 调用Condition的await()方法,将当前线程放入等待队列,释放锁
- 一定执行的释放锁动作。
nextGeneration()的代码如下:
private void nextGeneration() { // signal completion of last generation trip.signalAll(); // set up next generation count = parties; generation = new Generation(); }
使用Condition的signalAll()方法,唤醒全部等待线程
说完CyclicBarrier的原理之后,再对本篇的使用示例做一下描述:
- 线程1开始执行,调用await()方法,获得锁。此时count为3,count--,故count为2,index为2,调用Condition.await()方法,线程1进入等待队列,释放锁
- 线程2开始执行,过程与第一步相同,只是count减为1
- 线程3开始执行,获得锁,count减为0,达到拦截数量,调用nextGeneration()方法唤醒全部线程,释放自己持有的锁
- 线程1,2都被唤醒,根据锁竞争结果,依次执行完await()方法,最后释放锁
- 3个线程再往下执行自己的run()方法
原文链接:https://www.cnblogs.com/sunshine-ground-poems/p/10388355.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 最详细的java多线程教程来了 2020-06-08
- 系统化学习多线程(一) 2020-06-08
- 多线程:生产者消费者(管程法、信号灯法) 2020-06-01
- 如何合理地估算线程池大小? 2020-05-31
- 那些面试官必问的JAVA多线程和并发面试题及回答 2020-05-28
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