目录
CyclicBarrier是什么
- CyclicBarrier是一种同步辅助工具,字面意思就是循环栅栏,它允许一组线程在一个共同的屏障点彼此等待,所有线程到达屏障点后再全部同时执行。
- 当所有等待线程都被释放以后,CyclicBarrier可以被重用
CyclicBarrier的原理
CyclicBarrier的内部定义了一个ReentrantLock的对象,然后再利用这个ReentrantLock对象生成一个Condition的对象。每当一个线程调用CyclicBarrier的await方法时,首先把剩余屏障的线程数减1,然后判断剩余屏障数是否为0:如果不是,利用Condition的await方法阻塞当前线程;如果是,首先利用Condition的signalAll方法唤醒所有线程,最后重新生成Generation对象以实现屏障的循环使用。
CyclicBarrier的await源码
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock; //ReentrantLock锁
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count; //每次调用await()方法 减1
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration(); //重新生成Generation()
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
CyclicBarrier的使用
ExecutorService threadPool = Executors.newFixedThreadPool(5);
CyclicBarrier barrier = new CyclicBarrier(5,()->{
System.out.println("游戏结束");
});
CyclicBarrier的第二个参数可以设置每次使用完后执行的方法,当剩余屏障为0时,会执行该方法,然后执行await()之后的方法,可以用来线程同步
例子
package main.多线程.循环栅栏;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
CyclicBarrier barrier = new CyclicBarrier(5,()->{
System.out.println("开始下一次循环--------注意该方法调用的时刻");
});
threadPool.submit(()->{
System.out.println("玩家一:加载中");
try {
Thread.sleep(5000);
try {
System.out.println("玩家一:加载完成");
barrier.await();
System.out.println("玩家一:进入游戏");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
System.out.println("玩家二:加载中");
try {
Thread.sleep(4000);
try {
System.out.println("玩家二:加载完成");
barrier.await();
System.out.println("玩家二:进入游戏");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
System.out.println("玩家三:加载中");
try {
Thread.sleep(1500);
try {
System.out.println("玩家三:加载完成");
barrier.await();
System.out.println("玩家三:进入游戏");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
System.out.println("玩家四:加载中");
try {
Thread.sleep(7000);
try {
System.out.println("玩家四:加载完成");
barrier.await();
System.out.println("玩家四:进入游戏");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
System.out.println("玩家五:加载中");
try {
Thread.sleep(10000);
try {
System.out.println("玩家五:加载完成");
barrier.await();
System.out.println("玩家五:进入游戏");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
----------------------------------------------------------------------------------
//重复使用CyclicBarrier循环栅栏
threadPool.submit(()->{
try {
Thread.sleep(1000);
try {
System.out.println("玩家五:离开游戏");
barrier.await();
System.out.println("游戏结束");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
try {
Thread.sleep(1000);
try {
System.out.println("玩家四:离开游戏");
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
try {
Thread.sleep(3000);
try {
System.out.println("玩家三:离开游戏");
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
try {
Thread.sleep(4000);
try {
System.out.println("玩家二:离开游戏");
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadPool.submit(()->{
try {
Thread.sleep(5000);
try {
System.out.println("玩家一:离开游戏");
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
//结果
玩家一:加载中
玩家二:加载中
玩家三:加载中
玩家四:加载中
玩家五:加载中
玩家三:加载完成
玩家二:加载完成
玩家一:加载完成
玩家四:加载完成
玩家五:加载完成
开始下一次循环--------注意该方法调用的时刻
玩家五:进入游戏
玩家三:进入游戏
玩家二:进入游戏
玩家一:进入游戏
玩家四:进入游戏
玩家五:离开游戏
玩家四:离开游戏
玩家三:离开游戏
玩家二:离开游戏
玩家一:离开游戏
开始下一次循环--------注意该方法调用的时刻
游戏结束