java多线程 栅栏CyclicBarrier

CyclicBarrier
类介绍
A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

CyclicBarrier是一个同步工具类,它允许一组线程在到达某个栅栏点(common barrier point)互相等待,发生阻塞,直到最后一个线程到达栅栏点,栅栏才会打开,处于阻塞状态的线程恢复继续执行.它非常适用于一组线程之间必需经常互相等待的情况。CyclicBarrier字面理解是循环的栅栏,之所以称之为循环的是因为在等待线程释放后,该栅栏还可以复用。

示例一:简单模拟一下对战平台中玩家需要完全准备好了,才能进入游戏的场景。

public class BarrierDemo {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
final CyclicBarrier barrier = new CyclicBarrier(5);
for (int i = 0; i < 5; i++) {
service.execute(new Player("玩家" + i, barrier));
}
service.shutdown();
}
}

public class Player implements Runnable {
private final String name;
private final CyclicBarrier barrier;

public Player(String name, CyclicBarrier barrier) {
this.name = name;
this.barrier = barrier;
}

public void run() {
try {
TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
System.out.println(name + "已准备,等待其他玩家准备...");
barrier.await();
TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
System.out.println(name + "已加入游戏");
} catch (InterruptedException e) {
System.out.println(name + "离开游戏");
} catch (BrokenBarrierException e) {
System.out.println(name + "离开游戏");
}

}
}
输出结果:

玩家0已准备,等待其他玩家准备...
玩家2已准备,等待其他玩家准备...
玩家1已准备,等待其他玩家准备...
玩家4已准备,等待其他玩家准备...
玩家3已准备,等待其他玩家准备...
玩家4已加入游戏
玩家1已加入游戏
玩家0已加入游戏
玩家3已加入游戏
玩家2已加入游戏

构造函数
CyclicBarrier有两个构造函数:

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)

参数parties指定线程数量,当指定的线程值都到达栅栏点时,栅栏打开,线程恢复。需要注意的是,当指定的线程数量大于启动的线程数量,比如修改上例中的代码,只启动9个线程,那么所有的线程将一直处于等待状态。第二种情况是指定的线程数量小于启动的线程,上例代码,启动11个线程,那么当第十个线程到达栅栏点时,那么这十个线程就会恢复继续执行,而第十一个线程将一直处于阻塞状态。请大家自行修改代码验证。
CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。代码如下:
示例二

public class BarrierDemo2 {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
final CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
public void run() {
System.out.println("所有线程已到达栅栏点");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
for (int i = 0; i < 5; i++) {
service.execute(new Player("玩家" + i, barrier));
}
service.shutdown();
}
}

输出结果为:

玩家4已准备,等待其他玩家准备...
玩家2已准备,等待其他玩家准备...
玩家1已准备,等待其他玩家准备...
玩家0已准备,等待其他玩家准备...
玩家3已准备,等待其他玩家准备...
所有线程已到达栅栏点
玩家0已加入游戏
玩家1已加入游戏
玩家3已加入游戏
玩家4已加入游戏
玩家2已加入游戏

常用方法介绍
await()
Waits until all parties have invoked await on this barrier.

调用该方法会使当前线程在栅栏点发生阻塞,直到指定的线程数量都达到栅栏点时恢复执行

await(long timeout, TimeUnit unit)
Waits until all parties have invoked await on this barrier, or the specified waiting time elapses.

类似于await(),增加了超时时间参数。
参考如下代码:

public void run() {
try {
TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
System.out.println(name + "已准备,等待其他玩家准备...");
barrier.await(200, TimeUnit.MILLISECONDS);
TimeUnit.SECONDS.sleep(1 + (new Random().nextInt(3)));
System.out.println(name + "已加入游戏");
} catch (InterruptedException e) {
System.out.println(name + "离开游戏");
} catch (BrokenBarrierException e) {
System.out.println(name + "离开游戏");
} catch (TimeoutException e) {
System.out.println(name + "连接超时");
}
}

输出结果:

玩家3已准备,等待其他玩家准备...
玩家3连接超时
玩家0已准备,等待其他玩家准备...
玩家1已准备,等待其他玩家准备...
玩家0离开游戏
玩家1离开游戏
玩家4已准备,等待其他玩家准备...
玩家2已准备,等待其他玩家准备...
玩家4离开游戏
玩家2离开游戏

上面的代码修改了Player.java里面的run()方法,当barrier在等待点出等待超时时,会抛出TimeoutException异常,同时,位于该barrier上的其他线程也将毁抛出BrokenBarrierException异常。这里说明,barrier上的线程要么同时成功要么同时失败,不存在部分成功部分失败的场景。

getNumberWaiting()
Returns the number of parties currently waiting at the barrier.

返回当前在栅栏处等待的参与者数目。此方法主要用于调试和断言。

getParties()
Returns the number of parties required to trip this barrier.

该方法可以获得构造函数中指定的需要在栅栏点阻塞的线程数量

isBroken()
Queries if this barrier is in a broken state

查询此栅栏是否处于损坏状态。

reset()
Resets the barrier to its initial state.

将barrier重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个 BrokenBarrierException
---------------------
作者:小鱼儿Eason
来源:CSDN
原文:https://blog.csdn.net/yin380697242/article/details/53313622
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/moxiaotao/p/10117903.html