zoukankan      html  css  js  c++  java
  • CyclicBarrier总结

    一. CyclicBarrier简介
    1:CyclicBarrier(可重用屏障/栅栏) 类似于 CountDownLatch(倒计数闭锁),它能阻塞一组线程直到某个事件的发生。
    2:与闭锁的关键区别在于,所有的线程必须同时到达屏障位置,才能继续执行。
    3:闭锁用于等待事件,而屏障用于等待其他线程。
    4:CyclicBarrier 可以使一定数量的线程反复地在屏障位置处汇集。当线程到达屏障位置时将调用 await() 方法,这个方法将阻塞直到所有线程都到达屏障位置。如果所有线程都到达屏障位置,那么屏障将打开,此时所有的线程都将被释放,而屏障将被重置以便下次使用。
    5:CyclicBarrier 是一个同步辅助类,它允许一组线程相互等待直到所有线程都到达一个公共的屏障点。
    6:在程序中有固定数量的线程,这些线程有时候必须等待彼此,这种情况下,使用 CyclicBarrier 很有帮助。
    7:这个屏障之所以用循环修饰,是因为在所有的线程释放彼此之后,这个屏障是可以重新使用的。

    二:CyclicBarrier 的应用场景
    CyclicBarrier 常用于多线程分组计算。
    比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候就可以选择CyclicBarrier。

    三:常用API方法总结:

    1:CyclicBarrier(parties) 方法
    初始化相互等待的线程数量的构造方法。

    2:CyclicBarrier(parties,Runnable barrierAction) 方法
    初始化相互等待的线程数量以及屏障线程的构造方法。
    屏障线程的运行时机:等待的线程数量 =parties 之后,CyclicBarrier 打开屏障之前。
    例如在分组计算中,每个线程负责一部分计算,最终这些线程计算结束之后,交由屏障线程进行汇总计算。

    3:getParties() 方法
    获取 CyclicBarrier 打开屏障的线程数量。

    4:getNumberWaiting() 方法
    获取正在 CyclicBarrier 上等待的线程数量。

    5:await() 方法
    在 CyclicBarrier 上进行阻塞等待,直到发生以下情形之一。
    在 CyclicBarrier 上等待的线程数量达到 parties,则所有线程被释放,继续执行。
    当前线程被中断,则抛出 InterruptedException 异常,并停止等待,继续执行。
    其他等待的线程被中断,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行。
    其他等待的线程超时,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行。
    其他线程调用 CyclicBarrier.reset() 方法,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行。
    线程调用 await() 表示自己已经到达栅栏。
    BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程await() 时被中断或者超时。

    6:await(timeout,TimeUnit) 方法
    在 CyclicBarrier 上进行限时的阻塞等待,直到发生以下情形之一。
    在 CyclicBarrier 上等待的线程数量达到 parties,则所有线程被释放,继续执行。
    当前线程被中断,则抛出 InterruptedException 异常,并停止等待,继续执行。
    当前线程等待超时,则抛出 TimeoutException 异常,并停止等待,继续执行。
    其他等待的线程被中断,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行。
    其他等待的线程超时,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行。
    其他线程调用 CyclicBarrier.reset() 方法,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行

    7:isBroken() 方法
    获取是否破损标志位 broken 的值,此值有以下几种情况。
    CyclicBarrier 初始化时,broken=false,表示屏障未破损。
    如果正在等待的线程被中断,则 broken=true,表示屏障破损。
    如果正在等待的线程超时,则 broken=true,表示屏障破损。
    如果有线程调用 CyclicBarrier.reset() 方法,则 broken=false,表示屏障回到未破损状态。

    8:reset() 方法
    使 CyclicBarrier 回归初始状态,它做了两件事。
    如果有正在等待的线程,则会抛出 BrokenBarrierException 异常,且这些线程停止等待,继续执行。
    将是否破损标志位 broken 置为 false。

    四:CyclicBarrier 和 CountDownLatch 的区别

    CountDownLatch 是一个线程(或者多个),等待另外N个线程完成某个事情之后才能执行;CyclicBarrie是N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
    CountDownLatch 的计数器只能使用一次。而 CyclicBarrier的计数器可以使用 reset()方法重置;CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
    CountDownLatch 采用减计数方式;CyclicBarrier 采用加计数方式。

    五:使用 CyclicBarrier 的注意事项
    CyclicBarrier 使用独占锁来执行 await() 方法,并发性可能不是很高。
    如果在等待过程中,线程被中断了,就抛出异常。
    但如果中断的线程所对应的 CyclicBarrier 不是这一代,比如在最后一次线程执行 signalAll 后,并且更新了这个 " 代 " 对象。在这个区间,这个线程被中断了,那么, JDK 认为任务已经完成,不必在乎中断,就只打了一个中断 interrupt() 标记。
    如果线程被其他的 CyclicBarrier 唤醒,那么 g 肯定等于 generation,这个事件就不能 return 了,而是继续循环阻塞。
    反之,如果是当前 CyclicBarrier 唤醒,就返回线程在 CyclicBarrier 的下标,表示完成了一次冲过屏障的过程。
    CyclicBarrier 的 await() 方法是使用 ReentrantLock 和 Condition 控制实现的。
    当调用 CyclicBarrier 的 await() 方法会间接调用 ConditionObject 的 await() 方法,会向 Condition 的等待队列中加入元素,当屏障关闭后首先执行指定的barrierAction(),然后依次执行等待队列中的任务,有先后顺序。
    CyclicBarrier 类中加锁的方法有 dowait(),isBroken(),reset(),getNumberWaiting()。

    六: 总结
    CyclicBarrier 的用途是让一组线程互相等待,直到全部到达某个公共屏障点才开始继续工作。
    CyclicBarrier 是可以重复利用的。
    在等待的只要有一个线程发生中断,则其它线程就会被唤醒继续正常运行。
    CyclicBarrier 指定的任务是进行 barrier 处最后一个线程来调用的,如果在执行这个任务发生异常时,则会传播到此线程,其它线程不受影响继续正常运行。

    郭慕荣博客园
  • 相关阅读:
    我劝你不要记账
    富人不存钱
    1w+的心路历程
    简历这么写才对!
    Android 开发凉了吗!
    三个思维转变
    说一说赚钱
    【原】Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法(Matt Galloway著)读书笔记(二)
    【原】Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法(Matt Galloway著)读书笔记(一)
    【原】iOS开发进阶(唐巧)读书笔记(二)
  • 原文地址:https://www.cnblogs.com/jelly12345/p/12111094.html
Copyright © 2011-2022 走看看