java.lang.Object java.util.concurrent.CyclicBarrier
public class CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 支持一个可选的 Runnable
命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
示例用法:下面是一个在并行分解设计中使用 barrier 的例子:
class Solver { final int N; final float[][] data; final CyclicBarrier barrier; class Worker implements Runnable { int myRow; Worker(int row) { myRow = row; } public void run() { while (!done()) { processRow(myRow); try { barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } } } } public Solver(float[][] matrix) { data = matrix; N = matrix.length; barrier = new CyclicBarrier(N, new Runnable() { public void run() { mergeRows(...); } }); for (int i = 0; i < N; ++i) new Thread(new Worker(i)).start(); waitUntilDone(); } }在这个例子中,每个 worker 线程处理矩阵的一行,在处理完所有的行之前,该线程将一直在屏障处等待。处理完所有的行之后,将执行所提供的
Runnable
屏障操作,并合并这些行。如果合并者确定已经找到了一个解决方案,那么
done() 将返回
true,所有的 worker 线程都将终止。
如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await()
都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:
if (barrier.await() == 0) { // log the completion of this iteration }
对于失败的同步尝试,CyclicBarrier 使用了一种要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过 BrokenBarrierException
(如果它们几乎同时被中断,则用 InterruptedException
)以反常的方式离开。
内存一致性效果:线程中调用 await()
之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 紧跟在从另一个线程中对应 await()
成功返回的操作。
CountDownLatch
构造方法摘要 | |
---|---|
CyclicBarrier(int parties) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。 |
|
CyclicBarrier(int parties, Runnable barrierAction) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。 |
方法摘要 | |
---|---|
int |
await() 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 |
int |
await(long timeout, TimeUnit unit) 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。 |
int |
getNumberWaiting() 返回当前在屏障处等待的参与者数目。 |
int |
getParties() 返回要求启动此 barrier 的参与者数目。 |
boolean |
isBroken() 查询此屏障是否处于损坏状态。 |
void |
reset() 将屏障重置为其初始状态。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
构造方法详细信息 |
---|
public CyclicBarrier(int parties, Runnable barrierAction)
parties
- 在启动 barrier 前必须调用
await()
的线程数
barrierAction
- 在启动 barrier 时执行的命令;如果不执行任何操作,则该参数为
null
IllegalArgumentException
- 如果
parties
小于 1
public CyclicBarrier(int parties)
parties
- 在启动 barrier 前必须调用
await()
的线程数
IllegalArgumentException
- 如果
parties
小于 1
方法详细信息 |
---|
public int getParties()
public int await() throws InterruptedException, BrokenBarrierException
如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
reset()
。 如果当前线程:
InterruptedException
,并且清除当前线程的已中断状态。
如果在线程处于等待状态时 barrier 被 reset()
,或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException
异常。
如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException
异常,并将 barrier 置于损坏状态。
如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
getParties()
- 1 指示将到达的第一个线程,零指示最后一个到达的线程
InterruptedException
- 如果当前线程在等待时被中断
BrokenBarrierException
- 如果
另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者在调用
await
时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
reset()
。 如果当前线程:
InterruptedException
,并且清除当前线程的已中断状态。
如果超出指定的等待时间,则抛出 TimeoutException
异常。如果该时间小于等于零,则此方法根本不会等待。
如果在线程处于等待状态时 barrier 被 reset()
,或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException
异常。
如果任何线程在等待时被中断,则其他所有等待线程都将抛出 BrokenBarrierException
,并将屏障置于损坏状态。
如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
timeout
- 等待 barrier 的时间
unit
- 超时参数的时间单位
getParties()
- 1 指示第一个将要到达的线程,零指示最后一个到达的线程
InterruptedException
- 如果当前线程在等待时被中断
TimeoutException
- 如果超出了指定的超时时间
BrokenBarrierException
- 如果
另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者调用
await
时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。
public boolean isBroken()
true
;否则返回
false
。
public void reset()
BrokenBarrierException
。注意,在由于其他原因造成损坏
之后,实行重置可能会变得很复杂;此时需要使用其他方式重新同步线程,并选择其中一个线程来执行重置。与为后续使用创建一个新 barrier 相比,这种方法可能更好一些。
public int getNumberWaiting()
await()
中的参与者数目。