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 处最后一个线程来调用的,如果在执行这个任务发生异常时,则会传播到此线程,其它线程不受影响继续正常运行。

    郭慕荣博客园
  • 相关阅读:
    27. Remove Element
    26. Remove Duplicates from Sorted Array
    643. Maximum Average Subarray I
    674. Longest Continuous Increasing Subsequence
    1. Two Sum
    217. Contains Duplicate
    448. Find All Numbers Disappeared in an Array
    566. Reshape the Matrix
    628. Maximum Product of Three Numbers
    UVa 1349 Optimal Bus Route Design (最佳完美匹配)
  • 原文地址:https://www.cnblogs.com/jelly12345/p/12111094.html
Copyright © 2011-2022 走看看