CyclicBarrier 用于使线程相互等待。当不同的线程处理一部分计算,当所有线程都完成执行后,需要在父线程中合并结果时使用。换句话说,当多个线程执行不同的子任务并且需要组合这些子任务的输出以形成最终输出时,使用CyclicBarrier。执行完成后,线程调用await()方法并等待其他线程到达屏障。一旦所有线程都到达,障碍就会为线程继续前进提供道路。
Working of CyclicBarrier
CyclicBarriers 在java.util.concurrent 包中定义。首先创建 CyclicBarriers 的新实例,指定屏障应等待的线程数。
CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads);
每个线程都会进行一些计算,并在完成执行后调用 await() 方法,如下所示:
public void run() { // thread does the computation newBarrier.await(); }
CyclicBarrier 的工作原理:
一旦调用 await() 的线程数等于线程数,屏障就会为等待线程提供一条道路。 CyclicBarrier 也可以通过所有线程到达屏障后执行的某些操作来初始化。此操作可以组合/利用在屏障中等待的各个线程的计算结果。
Runnable action = ... //action to be performed when all threads reach the barrier; CyclicBarrier newBarrier = new CyclicBarrier(numberOfThreads, action);
CyclicBarrier的重要方法:
- getParties:返回触发此障碍所需的参与方数量。
Syntax:public int getParties()
返回:
跨越这一障碍所需的参与方数量 - reset:将屏障重置为其初始状态。
Syntax:public void reset()
返回:
void 但将屏障重置为其初始状态。如果任何一方当前在屏障处等待,他们将返回 BrokenBarrierException。 - isBroken:查询此屏障是否处于损坏状态。
Syntax:public boolean isBroken()
返回:
如果一方或多方由于自构建或上次重置以来的中断或超时而突破此障碍,或者由于异常导致障碍操作失败,则为 true;否则为假。 - getNumberWaiting:返回当前在屏障处等待的各方数量。
Syntax:public int getNumberWaiting()
返回:
await()中当前被阻止的政党数量 - await:等待所有各方都在此屏障上调用等待。
Syntax:public int await() throws InterruptedException, BrokenBarrierException
返回:
当前线程的到达索引,其中索引getParties() - 1 表示第一个到达,0 表示最后一个到达。 - await:等待直到所有各方都在此屏障上调用await,或者指定的等待时间过去。
Syntax:public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
返回:
当前线程的到达索引,其中索引getParties() - 1表示第一个到达,0表示最后一个到达
//JAVA program to demonstrate execution on Cyclic Barrier
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
class Computation1 implements Runnable
{
public static int product = 0;
public void run()
{
product = 2 * 3;
try
{
Tester.newBarrier.await();
}
catch (InterruptedException | BrokenBarrierException e)
{
e.printStackTrace();
}
}
}
class Computation2 implements Runnable
{
public static int sum = 0;
public void run()
{
// check if newBarrier is broken or not
System.out.println("Is the barrier broken? - " + Tester.newBarrier.isBroken());
sum = 10 + 20;
try
{
Tester.newBarrier.await(3000, TimeUnit.MILLISECONDS);
// number of parties waiting at the barrier
System.out.println("Number of parties waiting at the barrier "+
"at this point = " + Tester.newBarrier.getNumberWaiting());
}
catch (InterruptedException | BrokenBarrierException e)
{
e.printStackTrace();
}
catch (TimeoutException e)
{
e.printStackTrace();
}
}
}
public class Tester implements Runnable
{
public static CyclicBarrier newBarrier = new CyclicBarrier(3);
public static void main(String[] args)
{
// parent thread
Tester test = new Tester();
Thread t1 = new Thread(test);
t1.start();
}
public void run()
{
System.out.println("Number of parties required to trip the barrier = "+
newBarrier.getParties());
System.out.println("Sum of product and sum = " + (Computation1.product +
Computation2.sum));
// objects on which the child thread has to run
Computation1 comp1 = new Computation1();
Computation2 comp2 = new Computation2();
// creation of child thread
Thread t1 = new Thread(comp1);
Thread t2 = new Thread(comp2);
// moving child thread to runnable state
t1.start();
t2.start();
try
{
Tester.newBarrier.await();
}
catch (InterruptedException | BrokenBarrierException e)
{
e.printStackTrace();
}
// barrier breaks as the number of thread waiting for the barrier
// at this point = 3
System.out.println("Sum of product and sum = " + (Computation1.product +
Computation2.sum));
// Resetting the newBarrier
newBarrier.reset();
System.out.println("Barrier reset successful");
}
}
输出:
<Number of parties required to trip the barrier = 3 Sum of product and sum = 0 Is the barrier broken? - false Number of parties waiting at the barrier at this point = 0 Sum of product and sum = 36 Barrier reset successful
解释:(sum + Product) = 0 的值打印在控制台上,因为子线程还没有运行来设置 sum 和 Product 变量的值。接下来,(sum + Product) = 36 会打印在控制台上,因为子线程运行时设置了 sum 和 Product 的值。此外,屏障上等待的线程数量达到了3,因此屏障允许所有线程通过,最终打印出36。 “此时在屏障处等待的各方数量”的值 = 0,因为所有三个线程都已调用 await() 方法,因此屏障不再处于活动状态。最后newBarrier被重置,可以再次使用。
BrokenBarrierException
当任何等待线程离开屏障时,屏障就会中断。当一个或多个等待线程被中断或等待时间完成时,会发生这种情况,因为线程调用了超时的 await() 方法,如下所示:
newBarrier.await(1000, TimeUnit.MILLISECONDS); // thread calling this await() // methods waits for only 1000 milliseconds.
当屏障由于多个参与线程之一而破坏时,所有其他线程的 await() 方法将引发 BrokenThreadException。而已经在屏障中等待的线程则终止其 await() 调用。
Difference between a CyclicBarrier and a CountDownLatch
- CountDownLatch 在程序中只能使用一次(直到计数达到 0)。
- 一旦屏障中的所有线程被释放,CyclicBarrier 就可以一次又一次地使用。
参考:Oracle
相关用法
- Java Java.util.concurrent.RecursiveAction用法及代码示例
- Java Java.util.concurrent.Phaser用法及代码示例
- Java Java.util.concurrent.RecursiveTask用法及代码示例
- Java Java.util.ArrayDeque.add()用法及代码示例
- Java Java.util.ArrayDeque.addFirst()用法及代码示例
- Java Java.util.ArrayDeque.addLast()用法及代码示例
- Java Java.util.ArrayDeque.clear()用法及代码示例
- Java Java.util.ArrayDeque.clone()用法及代码示例
- Java Java.util.ArrayDeque.descendingIterator()用法及代码示例
- Java Java.util.ArrayDeque.element()用法及代码示例
- Java Java.util.ArrayDeque.getFirst()用法及代码示例
- Java Java.util.ArrayDeque.getLast()用法及代码示例
- Java Java.util.ArrayDeque.isEmpty()用法及代码示例
- Java Java.util.ArrayDeque.iterator()用法及代码示例
- Java Java.util.ArrayDeque.peek()用法及代码示例
- Java Java.util.ArrayDeque.peekFirst()用法及代码示例
- Java Java.util.ArrayDeque.peekLast()用法及代码示例
- Java Java.util.ArrayDeque.poll()用法及代码示例
- Java Java.util.ArrayDeque.pollFirst()用法及代码示例
- Java Java.util.ArrayDeque.pollLast()用法及代码示例
- Java Java.util.ArrayDeque.pop()用法及代码示例
- Java Java.util.ArrayDeque.push()用法及代码示例
- Java Java.util.ArrayDeque.remove()用法及代码示例
- Java Java.util.ArrayDeque.removeFirst()用法及代码示例
- Java Java.util.ArrayDeque.removeLast()用法及代码示例
注:本文由纯净天空筛选整理自佚名大神的英文原创作品 Java.util.concurrent.CyclicBarrier in Java。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。