Java并发源码分析之CyclicBarrier

关联文章:
关联文章:
Java并发源码分析之AQS及ReentrantLock
Java并发源码分析之Semaphore
Java并发源码分析之ReentrantReadWriteLock
Java并发源码分析之Condition
Java并发源码分析之CountDownLatch

工作原理概要

CyclicBarrier内部持有ReentrantLock和Condition对象,定义一个资源的值,然后开启与资源值相同数量的线程,线程运行时,调用await()方法,形成屏障,先到达屏障的线程会被阻塞,加入等待队列中等待。等到所有线程都到达屏障位置,等待的线程会被唤醒,才能继续执行。

使用demo

public class CyclicBarrierRunnable implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public CyclicBarrierRunnable(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        try {
            System.out.println("线程: " + Thread.currentThread().getName() + "开始执行任务, Time:" + LocalDateTime.now());
            int millis = (int) (Math.random() * 5000);
            Thread.sleep(millis);
            System.out.println("线程: " + Thread.currentThread().getName() + "执行任务完成, Time:" + LocalDateTime.now());
            this.cyclicBarrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程: " + Thread.currentThread().getName() + "退出, Time:" + LocalDateTime.now());
        }
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
        for (int i = 0; i < 10; i++) {
            executor.execute(new CyclicBarrierRunnable(cyclicBarrier));
        }
        
    }
}

开启了10个线程,每个线程执行的时间不同,最后会统一时间退出。
运行结果为:
运行结果
可以看到最后的退出时间一致的。

变量

 private final ReentrantLock lock = new ReentrantLock();
 // 等待队列
 private final Condition trip = lock.newCondition();
 // 资源值数量
 private final int parties;
 // 所有线程到达屏障时,执行该run方法
 private final Runnable barrierCommand;
 // 纪元,CyclicBarrier支持重复使用
 private Generation generation = new Generation();
 // 计数器,剩余未到达屏障的线程数量
 private int count;

构造函数

 // 
 public CyclicBarrier(int parties, Runnable barrierAction) {
     if (parties <= 0) throw new IllegalArgumentException();
     this.parties = parties;
     this.count = parties;
     this.barrierCommand = barrierAction;
 }

 // parties:资源值数量
 public CyclicBarrier(int parties) {
     this(parties, null);
 }

暂停执行方法解析

1、await()暂停执行入口

 public int await() throws InterruptedException, BrokenBarrierException {
     try {
         return dowait(false, 0L);
     } catch (TimeoutException toe) {
         throw new Error(toe);
     }
 }

2、dowait()暂停执行

 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()) {
             // 中断Barrier
             breakBarrier();
             // 抛出异常
             throw new InterruptedException();
         }

         // 当前线程已经到达屏障, 将计数器-1
         int index = --count;
         // 判断是否达到临界状态, 即所有线程都已经到达屏障, count = 0
         if (index == 0) {
             boolean ranAction = false;
             try {
                 final Runnable command = barrierCommand;
                 // 检查是否有额外动作要执行
                 if (command != null)
                     // 执行额外操作
                     command.run();
                 ranAction = true;
                 // 进入下一个纪元, 方法内部有调用signalAll唤醒所有等待的线程
                 nextGeneration();
                 return 0;
             } finally {
                 if (!ranAction)
                 	 // 关闭屏障
                     breakBarrier();
             }
         }
         
         // 如果没有达到临界状态, 则开始阻塞
         for (;;) {
             try {
             	 // 如果未超时需要阻塞
                 if (!timed)
                     // 将当前线程加入Condition的等待队列中阻塞
                     trip.await();
                 // 如果是带有超时的阻塞
                 else if (nanos > 0L)
                     nanos = trip.awaitNanos(nanos);
             } catch (InterruptedException ie) {
                 // 如果线程被打断, 并且屏障的状态正常
                 if (g == generation && ! g.broken) {
                     // 那么关闭屏障
                     breakBarrier();
                     throw ie;
                 } else {
                     // 走到这里说明,已经进入下一个纪元或者屏障被打破,中断线程
                     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();
     }
 }

3、breakBarrier()打破屏障

 private void breakBarrier() {
 	 // 设置纪元的状态为破坏状态
     generation.broken = true;
     // 重置计数器
     count = parties;
     // 唤醒所有等待队列中的线程
     trip.signalAll();
 }

4、nextGeneration()进入下个纪元

 // 开启下个纪元, 重置所有参数
 private void nextGeneration() {
     // 唤醒所有等待队列中的线程
     trip.signalAll();
     // 重置计数器
     count = parties;
     // 生成一个新的纪元
     generation = new Generation();
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值