CyclicBarrier 使用
CyclicBarrier是什么
CyclicBarrier也叫同步屏障,在JDK1.5被引入,可以让一组线程达到一个屏障时被阻塞,直到最后一个线程达到屏障时,所以被阻塞的线程才能继续执行。
CyclicBarrier好比一扇门,默认情况下关闭状态,堵住了线程执行的道路,直到所有线程都就位,门才打开,让所有线程一起通过。
应用场景
运动会男子100米决赛,8名选手。
每个运动员都就位后才开始。
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
List<Athlete> athleteList = new ArrayList<>();
athleteList.add(new Athlete(cyclicBarrier,"博尔特"));
athleteList.add(new Athlete(cyclicBarrier,"鲍威尔"));
athleteList.add(new Athlete(cyclicBarrier,"盖伊"));
athleteList.add(new Athlete(cyclicBarrier,"布雷克"));
athleteList.add(new Athlete(cyclicBarrier,"加特林"));
athleteList.add(new Athlete(cyclicBarrier,"苏炳添"));
athleteList.add(new Athlete(cyclicBarrier,"路人甲"));
athleteList.add(new Athlete(cyclicBarrier,"路人乙"));
Executor executor = Executors.newFixedThreadPool(8);
for (Athlete athlete : athleteList) {
executor.execute(athlete);
}
}
static class Athlete implements Runnable {
private CyclicBarrier cyclicBarrier;
private String name;
public Athlete(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
this.name = name;
}
@Override
public void run() {
System.out.println(name + "就位");
try {
cyclicBarrier.await();
Random random =new Random();
double time = random.nextDouble() + 9;
System.out.println(name + ": "+ time);
} catch (Exception e) {
}
}
}
}
实现原理:
使用ReentrantLock 实现
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;
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();
}
}
每当线程执行await,内部变量count减1,如果count!= 0,说明有线程还未到屏障处,则在锁条件变量trip上等待。
当count == 0时,说明所有线程都已经到屏障处,执行条件变量的signalAll方法唤醒等待的线程。
其中 nextGeneration方法可以实现屏障的循环使用:
重新生成Generation对象
恢复count值
与CountDownLatch 的区别
CountDownLatch 允许一个或多个线程等待一些特定的操作完成,而这些操作是在其它的线程中进行的,也就是说会出现 等待的线程 和 被等的线程 这样分明的角色;
CountDownLatch 构造函数中有一个 count 参数,表示有多少个线程需要被等待,对这个变量的修改是在其它线程中调用 countDown 方法,每一个不同的线程调用一次 countDown 方法就表示有一个被等待的线程到达,count 变为 0 时,latch(门闩)就会被打开,处于等待状态的那些线程接着可以执行;
CountDownLatch 是一次性使用的,也就是说latch门闩只能只用一次,一旦latch门闩被打开就不能再次关闭,将会一直保持打开状态,因此 CountDownLatch 类也没有为 count 变量提供 set 的方法;
参考:https://www.jianshu.com/p/424374d71b67
CyclicBarrier是Java并发工具类,用于同步屏障,使一组线程在执行前等待彼此。比如在运动会场景中,所有运动员必须就位才能开始比赛。它使用ReentrantLock实现内部同步,并通过Generation管理屏障状态。与CountDownLatch不同,CyclicBarrier可重用,适合多轮迭代的场景。
922

被折叠的 条评论
为什么被折叠?



