CyclicBarrier 支持可选的 Runnable 命令,该命令在每个障碍点运行一次,在派对中的最后一个线程到达之后,但在释放任何线程之前。这个 barrier action 对于在任何一方继续之前更新共享状态很有用。
示例用法:以下是在并行分解设计中使用障碍的示例:
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;
Runnable barrierAction = () -> mergeRows(...);
barrier = new CyclicBarrier(N, barrierAction);
List<Thread> threads = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
Thread thread = new Thread(new Worker(i));
threads.add(thread);
thread.start();
}
// wait until done
for (Thread thread : threads)
try {
thread.join();
} catch (InterruptedException ex) { }
}
} 这里,每个工作线程处理矩阵的一行,然后在屏障处等待,直到处理完所有行。处理完所有行后,将执行提供的 Runnable 屏障操作并合并行。如果合并确定已找到解决方案,则 done() 将返回 true 并且每个 worker 将终止。
如果屏障操作不依赖于执行时挂起的各方,则该方中的任何线程都可以在释放时执行该操作。为了促进这一点,await() 的每次调用都会返回该线程在屏障处的到达索引。然后您可以选择哪个线程应该执行屏障操作,例如:
if (barrier.await() == 0) {
// log the completion of this iteration
}
CyclicBarrier 对失败的同步尝试使用全有或无中断模型:如果一个线程由于中断、失败或超时而过早离开障碍点,所有其他在该障碍点等待的线程也将通过 BrokenBarrierException (或 InterruptedException )异常离开如果他们也大约在同一时间被打断)。
内存一致性影响:在调用 await() 发生在之前 操作之前线程中的操作是屏障操作的一部分,这反过来发生在之前从其他线程中相应的 await() 成功返回后的操作。
- 自从:
- 1.5
- 参见:
-
构造方法总结
构造方法构造方法描述CyclicBarrier(int parties) 创建一个新的CyclicBarrier,它将在给定数量的参与方(线程)等待时触发,并且在障碍触发时不执行预定义的操作。CyclicBarrier(int parties, Runnable barrierAction) 创建一个新的CyclicBarrier,当给定数量的参与方(线程)等待它时,它将触发,并在触发障碍时执行给定的障碍操作,由进入障碍的最后一个线程执行。 -
方法总结
-
构造方法详细信息
-
CyclicBarrier
创建一个新的CyclicBarrier,当给定数量的参与方(线程)等待它时,它将触发,并在触发障碍时执行给定的障碍操作,由进入障碍的最后一个线程执行。- 参数:
parties- 在屏障被触发之前必须调用await()的线程数barrierAction- 当屏障被触发时执行的命令,或者null如果没有动作- 抛出:
IllegalArgumentException- 如果parties小于 1
-
CyclicBarrier
public CyclicBarrier(int parties) 创建一个新的CyclicBarrier,它将在给定数量的参与方(线程)等待时触发,并且在障碍触发时不执行预定义的操作。- 参数:
parties- 在屏障被触发之前必须调用await()的线程数- 抛出:
IllegalArgumentException- 如果parties小于 1
-
-
方法详情
-
getParties
public int getParties()返回触发此障碍所需的参与方数量。- 返回:
- 突破这一障碍所需的参与方数量
-
await
等待所有 parties 在此屏障上调用await。如果当前线程不是最后一个到达的线程,则出于线程调度目的而禁用它并处于休眠状态,直到发生以下情况之一:
如果当前线程:
- 在进入此方法时设置其中断状态;或者
- 等待时是interrupted
InterruptedException并清除当前线程的中断状态。如果在任何线程等待时屏障为
reset(),或者在调用await时屏障为 被打破,或者在任何线程等待时屏障为 被打破,则抛出BrokenBarrierException。如果任何线程在等待时为 interrupted,则所有其他等待线程将抛出
BrokenBarrierException并将屏障置于中断状态。如果当前线程是最后一个到达的线程,并且在构造方法中提供了非空屏障操作,则当前线程在允许其他线程继续之前运行该操作。如果在屏障操作期间发生异常,则该异常将在当前线程中传播,并且屏障将置于中断状态。
- 返回:
-
当前线程的到达索引,其中索引
getParties() - 1表示第一个到达,零表示最后一个到达 - 抛出:
InterruptedException- 如果当前线程在等待时被中断BrokenBarrierException- 如果 another 线程在当前线程等待时被中断或超时,或者屏障被重置,或者屏障在调用await时被破坏,或者屏障操作(如果存在)由于异常而失败
-
await
public int await(long timeout, TimeUnit unit) throws InterruptedException , BrokenBarrierException , TimeoutException 等待直到所有 parties 在此屏障上调用await,或者指定的等待时间过去。如果当前线程不是最后一个到达的线程,则出于线程调度目的而禁用它并处于休眠状态,直到发生以下情况之一:
如果当前线程:
- 在进入此方法时设置其中断状态;或者
- 等待时是interrupted
InterruptedException并清除当前线程的中断状态。如果指定的等待时间过去,则抛出
TimeoutException。如果时间小于或等于零,则该方法根本不会等待。如果在任何线程等待时屏障为
reset(),或者在调用await时屏障为 被打破,或者在任何线程等待时屏障为 被打破,则抛出BrokenBarrierException。如果任何线程在等待时为 interrupted,则所有其他等待线程将抛出
BrokenBarrierException并将屏障置于中断状态。如果当前线程是最后一个到达的线程,并且在构造方法中提供了非空屏障操作,则当前线程在允许其他线程继续之前运行该操作。如果在屏障操作期间发生异常,则该异常将在当前线程中传播,并且屏障将置于中断状态。
- 参数:
timeout- 等待屏障的时间unit- 超时参数的时间单位- 返回:
-
当前线程的到达索引,其中索引
getParties() - 1表示第一个到达,零表示最后一个到达 - 抛出:
InterruptedException- 如果当前线程在等待时被中断TimeoutException- 如果指定的超时结束。在这种情况下,障碍将被打破。BrokenBarrierException- 如果 another 线程在当前线程等待时被中断或超时,或者屏障被重置,或者屏障在调用await时被破坏,或者屏障操作(如果存在)由于异常而失败
-
isBroken
public boolean isBroken()查询此屏障是否处于损坏状态。- 返回:
true如果一方或多方由于构建或上次重置后的中断或超时而突破此屏障,或者屏障操作因异常而失败;false否则。
-
reset
public void reset()将屏障重置为其初始状态。如果目前有任何一方正在屏障处等待,他们将返回BrokenBarrierException。请注意,重置 after 由于其他原因发生的破损执行起来可能很复杂;线程需要以其他方式重新同步,并选择一个来执行重置。相反,创建一个新的屏障以供后续使用可能更可取。 -
getNumberWaiting
public int getNumberWaiting()返回当前在屏障处等待的参与方数量。此方法主要用于调试和断言。- 返回:
-
当前在
await()中被阻止的派对数量
-