CyclicBarrier:是一个同步辅助类。它允许2个或多个线程在某个点上进行同步。这个类和CountDownLatch类型,但也有不同之处,使之成为更强大的类。
CyclicBarrier类使用一个整数型进行初始化,这个数是需要在某个点上同步的线程数。当一个线程到达指定的点后,它将调用await()方法等待其他的线程。当线程调用await()方法后,CyclicBarrier类将阻塞这个线程并使之休眠直到所有其他线程到达。当最后一个线程调用CyclicBarrier类有一个很有意义的改进,即它可以传入另一个Runnable对象作为初始化参数。当所有的线程都到达集合点后,CyclicBarrie类将这个Runnable 对象作为线程执行。
CyclicBarrier在等待之后,所有的线程继续执行自己的方法,CountDownLatch不行 ,执行完之后 只能把变量减一,然后去唤醒主线程去执行任务。
public class Player implements Runnable{
private CyclicBarrier cyclicBarrier;
public Player(CyclicBarrier cyclicBarrier) {
super();
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"已准备好");
try {
cyclicBarrier.await(); //等待其他线程执行完毕
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"开始出发");
}
public static void main(String[] args) {
//Runnable 会等到所有的线程执行完 然后在执行
CyclicBarrier cyclicBarrier = new CyclicBarrier(20,new Runnable() {
@Override
public void run() {
System.out.println("比赛开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
for(int i=1;i<21;i++){
new Thread(new Player(cyclicBarrier),"选手"+i).start();;
}
}
}
输出结果:
选手1已准备好
选手3已准备好
选手2已准备好
选手5已准备好
选手4已准备好
选手6已准备好
选手7已准备好
选手9已准备好
选手8已准备好
选手10已准备好
选手11已准备好
选手12已准备好
选手13已准备好
选手14已准备好
选手15已准备好
选手16已准备好
选手17已准备好
选手18已准备好
选手20已准备好
选手19已准备好
比赛开始
选手19开始出发
选手10开始出发
选手14开始出发
选手17开始出发
选手9开始出发
选手18开始出发
选手8开始出发
选手7开始出发
选手6开始出发
选手4开始出发
选手1开始出发
选手5开始出发
选手3开始出发
选手2开始出发
选手20开始出发
选手16开始出发
选手15开始出发
选手13开始出发
选手12开始出发
选手11开始出发
源码:
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
//当index 为0 时 执行 CyclicBarrier 的Runnnable 的方法
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();//唤醒所有线程
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos); // 挂起线程
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}