千家信息网

Java中的CyclicBarrier源码分析

发表于:2024-10-25 作者:千家信息网编辑
千家信息网最后更新 2024年10月25日,这篇文章主要介绍了Java中的CyclicBarrier源码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中的CyclicBarrier源码分析文章都会有所收
千家信息网最后更新 2024年10月25日Java中的CyclicBarrier源码分析

这篇文章主要介绍了Java中的CyclicBarrier源码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中的CyclicBarrier源码分析文章都会有所收获,下面我们一起来看看吧。

    CyclicBarrier简介

    对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。

    对于CyclicBarrier,假设有一家公司要全体员工进行团建活动,活动内容为翻越三个障碍物,每一个人翻越障碍物所用的时间是不一样的。但是公司要求所有人在翻越当前障碍物之后再开始翻越下一个障碍物,也就是所有人翻越第一个障碍物之后,才开始翻越第二个,以此类推。类比地,每一个员工都是一个"其他线程"。当所有人都翻越的所有的障碍物之后,程序才结束。而主线程可能早就结束了,这里我们不用管主线程。

    CyclicBarrier源码分析

    类的继承关系

    CyclicBarrier没有显示继承哪个父类或者实现哪个父接口, 所有AQS和重入锁不是通过继承实现的,而是通过组合实现的。

    public class CyclicBarrier {}```  ### 类的内部类CyclicBarrier类存在一个内部类Generation,每一次使用的CycBarrier可以当成Generation的实例,其源代码如下```javaprivate static class Generation {boolean broken = false;}

    说明: Generation类有一个属性broken,用来表示当前屏障是否被损坏。

    类的属性

    public class CyclicBarrier {/** The lock for guarding barrier entry */// 可重入锁private final ReentrantLock lock = new ReentrantLock();/** Condition to wait on until tripped */// 条件队列private final Condition trip = lock.newCondition();/** The number of parties */// 参与的线程数量private final int parties;/* The command to run when tripped */// 由最后一个进入 barrier 的线程执行的操作private final Runnable barrierCommand;/** The current generation */// 当前代private Generation generation = new Generation();// 正在等待进入屏障的线程数量private int count;}

    说明: 该属性有一个为ReentrantLock对象,有一个为Condition对象,而Condition对象又是基于AQS的,所以,归根到底,底层还是由AQS提供支持。

    类的构造函数

    CyclicBarrier(int, Runnable)型构造函数

    public CyclicBarrier(int parties, Runnable barrierAction) {// 参与的线程数量小于等于0,抛出异常if (parties <= 0) throw new IllegalArgumentException();// 设置partiesthis.parties = parties;// 设置countthis.count = parties;// 设置barrierCommandthis.barrierCommand = barrierAction;}

    说明: 该构造函数可以指定关联该CyclicBarrier的线程数量,并且可以指定在所有线程都进入屏障后的执行动作,该执行动作由最后一个进行屏障的线程执行。

    CyclicBarrier(int)型构造函数

    public CyclicBarrier(int parties) {// 调用含有两个参数的构造函数this(parties, null);}

    说明: 该构造函数仅仅执行了关联该CyclicBarrier的线程数量,没有设置执行动作。

    核心函数 - dowait函数

    此函数为CyclicBarrier类的核心函数,CyclicBarrier类对外提供的await函数在底层都是调用该了doawait函数,

    其源代码如下:

    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) { // 正在等待进入屏障的线程数量为0,所有线程都已经进入// 运行的动作标识boolean ranAction = false;try {// 保存运行动作final Runnable command = barrierCommand;if (command != null) // 动作不为空// 运行command.run();// 设置ranAction状态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) // 设置了等待时间,并且等待时间大于0// 等待指定时长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) { // 设置了等待时间,并且等待时间小于0// 损坏屏障breakBarrier();// 抛出异常throw new TimeoutException();}}} finally {// 释放锁lock.unlock();}}

    核心函数 - nextGeneration函数

    此函数在所有线程进入屏障后会被调用,即生成下一个版本,所有线程又可以重新进入到屏障中,

    其源代码如下:

    private void nextGeneration() {// signal completion of last generation// 唤醒所有线程trip.signalAll();// set up next generation// 恢复正在等待进入屏障的线程数量count = parties;// 新生一代generation = new Generation();}

    在此函数中会调用AQS的signalAll方法,即唤醒所有等待线程。如果所有的线程都在等待此条件,则唤醒所有线程。

    其源代码如:

    public final void signalAll() {if (!isHeldExclusively()) // 不被当前线程独占,抛出异常throw new IllegalMonitorStateException();// 保存condition队列头节点Node first = firstWaiter;if (first != null) // 头节点不为空// 唤醒所有等待线程doSignalAll(first);}

    关于"Java中的CyclicBarrier源码分析"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"Java中的CyclicBarrier源码分析"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

    0