CyclicBarrier

[align=center]CyclicBarrier[/align]
官方解释:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(common barrier point).在涉及一组固定大小的线程程序中,这些线程必须不时地互相等待,此时CyclicBarrier很有用。因为barrier在释放等待线程后可以重用,所以称它为循环的barrier.
CyclicBarrier支持一个可选的Runnable命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作很有用.
CyclicBarrier和CountDownLatch不同,CyclicBarrier是当await数量到达了设定的数量后,才继续往下执行,在之前讲ThreadPoolExecutor的例子曾使用CyclicBarrier,例子中采用了CyclicBarrier来确保所有线程几乎同时开始运行.
CyclicBarrier(int):
设置parties,count及barrierCommand属性.
另一个构造器允许传入一个实现Runnable的对象,当await数量到达了设定的数量后,会首先执行此Runable对象.[到时候必须测试]
Await()
首先进行加锁操作,然后对count属性执行减1操作,如果减后的值等于0,则执行传入的Runnable对象。执行完毕后将ranAction设置为true,调用nextGeneration方法并返回0,nextGeneration方法主要调用trip condition的sigalAll;如果count减1后的值不等0,则调用trip Condition的await或await(设置时间)进入等待,直到trip Condition被唤醒,线程被interrupt或超时,从等待状态恢复后;它是基于ReentrantLock和Condition来实现,而CountDownLatch是使用Sync来实现同步.
官方讲解:
* <p>If the barrier action does not rely on the parties being suspended when
* it is executed, then any of the threads in the party could execute that
* action when it is released. To facilitate this, each invocation of
* {@link #await} returns the arrival index of that thread at the barrier.
* You can then choose which thread should execute the barrier action, for
* example:
* <pre> if (barrier.await() == 0) {
* // log the completion of this iteration
* }</pre>
如果线程不需要等待,没有关联性,那么当所有线程执行完后,在这里可以添加完成的一些操作
对于失败的同步尝试,CyclicBarrier 使用了一种快速失败的、要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么其他所有线程(甚至是那些尚未从以前的 await() 中恢复的线程)也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。

如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:
if (barrier.await() == 0) {
// log the completion of this iteration
}
CyclicBarrier(int parties)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作

CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。

await()
在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
await(long timeout, TimeUnit unit)
在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待。
getNumberWaiting()
返回当前在屏障处等待的参与者数目。
getParties()
返回要求启动此 barrier 的参与者数目。
isBroken()
查询此屏障是否处于损坏状态。
reset()
将屏障重置为其初始状态。
如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。
如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
返回:
到达的当前线程的索引,其中,索引 getParties() - 1 指示将到达的第一个线程,零指示最后一个到达的线程。
抛出:
InterruptedException - 如果当前线程在等待时被中断
BrokenBarrierException - 如果另一个 线程在当前线程等待时被中断,或者重置了 barrier,或者在调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。

public void reset()
将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个 BrokenBarrierException。注意,在由于其他原因造成损坏之后,实行重置可能会变得很复杂;此时需要使用其他方式重新同步线程,并选择其中一个线程来执行重置。与为后续使用创建一个新 barrier 相比,这种方法可能更好一些。
CyclicBarrier 和CountDownLatch区别:
CountDownLatch就像一扇门的锁,比如我这门在10把钥匙才能打开,那么现在有十个线程过来了,十个人各自做自己的事,等到第十个人到达,这个门就打了,然后才执行await()后面的事情.
CyclicBarrier就像一个公共屏障点,比如我这个公共屏障点需要十个线程,那么,只有当十个线程都到达的时候,公共屏障点的方法就会执行,然后才会执行await()后面的事情
官方解释:
CountDownLatch:一个对同步有帮助的类,它允许一个或多个线程等待只到这组操作在其他线程全部完成
CyclicBarrier: 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(common barrier point).
看官方解释差异性并不大.有些有整些乱七八糟的例子,真是汗了。
功能差差异不大,实现方式不同,countdown使用锁的机制,采用state信号量来维护他的线程数,CountDown采用递减的模式,当CountDown为0时,表示锁全部大开,大家从await()的地方进入.[基于Sync]
CyclicBarrier采用的递减的模式,当count 为0时,表示全部线程到达点,大家从await()的地方进入,它不需要调用countDown,它是采用await()自动维护其count[基于ReentrantLock]
当然其应用场景不同,比如在线程内部,我需要采用同步,那么我可以使用CountDown,然后await().
也可以采用CyclicBarrier的await().但是如果我要线程外部呢,我在所有工作都完成,然后我执行汇报给我的动作,那么在线程内部只需要计数countDown,然后在外部await()就可以了。如果线程间不需要互相等待,只是大家到某一个地点,然后再执行一个动作,那么采用countDown.
如果线程间需要互相等待,比如只有当所有人都到达时才执行一步,然后接下去又有一个逻辑….在屏障点需要执行其他逻辑等,那么采用CyclicBarrier,当然采用countDown也可以的,只是麻烦了一点.

从理论上来讲,CyclicBarrier可以实现同步实现机制,而不仅仅是一把锁。
以下是实例:

package org.cyclicbarrier;

import java.util.concurrent.CyclicBarrier;

public class Driver {

public static void main(String args[]) throws InterruptedException {
final int N= 10;
boolean flag = false;
CyclicBarrier cyclic = new CyclicBarrier(
N,
new AnonSystem(flag,N)

);//设置屏障点,主要是为了执行这个方法
for (int i = 0; i < N; ++i){ // create and start threads
print("工人"+i+"到了..");
new Thread(new Worker(cyclic,"工人"+i)).start();
}
}

private static void print(String message) {
// TODO Auto-generated method stub
System.out.println(message);
}
}


这是很简单的功能,我是项目经理,当员工全部到场了通知我一下,员工完成任务的时候也通知我一下.

package org.cyclicbarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Worker implements Runnable {

private String worker;
private final CyclicBarrier cyclic;

Worker(CyclicBarrier cyclic,String worker) {
this.cyclic = cyclic;
this.worker = worker;
}

public void run() {
try {
cyclic.await();
doWork();
cyclic.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}

void doWork() {
System.out.println(worker+":劳动完成");
}
}


大家一起到达,一起工作。


package org.cyclicbarrier;

public class AnonSystem implements Runnable{

boolean flag;
int N;
public AnonSystem(boolean flag,int N){
this.flag=flag;
this.N=N;
}
public void run() {
// TODO Auto-generated method stub
if(flag){
system("经理:[工人"+N+"个,已经完成工作]");
}else{
system("经理:[工人"+N+"个,已经到了]");
flag = true;
}
}

private void system(String str) {
System.out.println(str);
}
}



工人到达和完成工作发通知.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值