前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JUC】CyclicBarrier的了解和使用

【JUC】CyclicBarrier的了解和使用

作者头像
袁新栋-jeff.yuan
发布2020-08-26 14:10:21
2710
发布2020-08-26 14:10:21
举报

概念

权威指南

  • 一种同步辅助工具,它允许一组线程全部互相等待以到达一个公共的障碍点。CyclicBarriers在涉及固定大小的线程方的程序中很有用,该线程方有时必须互相等待。屏障被称为循环屏障, 因为它可以在释放等待线程之后重新使用。
  • CyclicBarrier支持可选的Runnable命令,该命令在聚会的最后一个线程到达之后但在释放任何线程之前,每个障碍点运行一次。此屏障操作对于在任何一方继续之前更新共享状态很有用。

个人理解

  • 给每个线程设置一个阈值,当每个线程逗达到这个阈值的时候才会去执行。
  • 再抽象一点的话,我们去游乐园做船,这个船坐满的时候才会开出去。不坐满的话来的早的人就得等待来的晚的的人。所以这些人也就是会互相等待的。当人坐满的时候才会出发去岛上。这个船还可以重复被使用,当这批人被送走后,还可以承载下一批人。也就是CyclicBarrier的重复使用。

源码

常用方法和构造方法

  • 核心源码
  1. 在CyclicBarrier初始化时,设置栅栏数(new CyclicBarrier( int parties)),每有一个线程执行await方法(用Condition的await阻塞),栅栏就减少一个,直到减少到0,取消等待,唤醒线程(用Condition的signalAll唤醒)
  2. 任何一个线程被interrupt打断,Condition也会调用signalAll方法唤醒所有阻塞的线程。
  3. 有reset方法可以还原。(这也是和counDownLatch的最大的区别之一)
  4. 大概介绍:详细介绍的文章:点击此处
代码语言:javascript
复制
 /**
     * Main barrier code, covering the various policies.
     */
    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();
            …………………………………………
        }

SHOW ME CODE

代码语言:javascript
复制
package JUC;

import lombok.SneakyThrows;

import java.awt.*;
import java.util.concurrent.CyclicBarrier;

/**
 * @authoryuanxindong
 * @date: 2020/6/18 11:53 下午
 */
public class CyclicBarrierDemo implements Runnable{
    private int  timeOut ;
    private CyclicBarrier cyclicBarrier;

    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;

    }
    public  static class innerCyclicBarrierDemo  implements Runnable{
        @Override
        public void run() {
            System.out.println("最后执行的方法+");
        }
    }

    public CyclicBarrierDemo(int timeOut,CyclicBarrier cyclicBarrier) {
        this.timeOut = timeOut;
        this.cyclicBarrier = cyclicBarrier;
    }


    public static void main(String[] args) {
        // 启用一个CyclicBarrier,然后进行加载。
        CyclicBarrier cyclicBarrier =new CyclicBarrier(3,new innerCyclicBarrierDemo());
        long startTime = System.currentTimeMillis();
        CyclicBarrierDemo cyclicBarrierDemo = new CyclicBarrierDemo(1000,cyclicBarrier);
        Thread thread = new Thread(cyclicBarrierDemo);
        CyclicBarrierDemo cyclicBarrierDemo2 = new CyclicBarrierDemo(2000,cyclicBarrier);
        Thread thread1 = new Thread(cyclicBarrierDemo2);
        CyclicBarrierDemo cyclicBarrierDemo3 = new CyclicBarrierDemo(3000,cyclicBarrier);
        Thread thread2 = new Thread(cyclicBarrierDemo3);
           thread.start();
           thread1.start();
           thread2.start();


        System.out.println("所有线程执行结束执行时间:"+(System.currentTimeMillis() -startTime));
    }
    @SneakyThrows
    @Override
    public void run() {
        System.out.println("开始执行:「」"+Thread.currentThread().getName()+System.currentTimeMillis());
        Thread.sleep(timeOut);
      long watingTime = System.currentTimeMillis();
        System.out.println("等待:「」"+Thread.currentThread().getName()+watingTime);
        cyclicBarrier.await();
        System.out.println("完成:「」"+Thread.currentThread().getName() +"    time:    "+ (System.currentTimeMillis()-watingTime));
    }

}

执行结果

代码语言:javascript
复制
开始执行:「」Thread-01592752948830
开始执行:「」Thread-11592752948830
所有线程执行结束执行时间:2
开始执行:「」Thread-21592752948831
等待:「」Thread-01592752949833
等待:「」Thread-11592752950835
等待:「」Thread-21592752951836
最后执行的方法+
完成:「」Thread-2    time:    0
完成:「」Thread-0    time:    2003
完成:「」Thread-1    time:    1001
Disconnected from the target VM, address: '127.0.0.1:58105', transport: 'socket'

Process finished with exit code 0
  • 我们细细的品一品:为什么线程2等待的时间最短呢? 因为他是做后一个执行完的,他不用等待别人而是执行快的在等待他。

Code analysis

  • 代码中我们分别给了3个线程,每个线程分别让执行不同的时间,然后通过调用CyclicBarrier的await方法,进行栏栅,第一个执行完后第一个进到栏栅状态所以等待第二个到达的时候第一个线已经等待了大约1000ms了,但是 第三个在此刻执行了2000MS,还有1000ms没有执行,所以还需等待第三个线程池,所以这个过程,第一个线程等待后两个线程大概用了2000MS 第二个等待随后一个线程大概用了1000s,只有第三个线程没有等待时间,在线程状态切换和执行的时候浪费了1MS。
  • 从上面我们也可以看到我们将一个RunAble初始化后,他会在最后一次线程等待结束后立马执行。并且是在线程本身的任务之前执行的。
  • 通过上面的分析,我们也证明了CyclicBarrier的功能。

总结

  1. CyclicBarrierd可以让多个线程之间相互等待
  2. 也可以,设置一个当所有线程都达到栏栅时再执行一个线程。(上面的例子,当船上满人的时候,这个时候船就会开动,这个开动就是Runable要执行的任务)
  3. CyclicBarrierd的栏栅是可以循环使用的,所以也叫回环栏栅。

参考资料

  1. https://blog.csdn.net/qq_17305249/article/details/78081002 (底层分析)
  2. https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CyclicBarrier.html(基本使用)
  3. https://blog.csdn.net/HalfImmortal/article/details/106796659(重点推荐)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
    • 权威指南
      • 个人理解
      • 源码
        • 常用方法和构造方法
        • SHOW ME CODE
          • 执行结果
            • Code analysis
            • 总结
            • 参考资料
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档