本文是视频https://www.bilibili.com/video/av81181427 的笔记
循环屏障
前一篇中,我们讲了多线程中的计数器。这里我们来讲循环屏障。
其实循环屏障的功能和计数器很像,它可以看成是计数器的countdown和await方法的组合。但是这就是区别所在:如果你把countDownLatch的await设置了主线程,那么就可以实现主线程等子线程执行完了之后再执行的效果;而循环屏障是统一了子线程之间的执行,也就是说如果要阻塞主线程的话,需要将循环屏障放在子线程任务完成之后、放在主线程创建完子线程之后
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
Thread.sleep(new Double(Math.random() * 3000).longValue());
System.out.println(Thread.currentThread().getName() + "玩家准备就绪");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "玩家选择英雄");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
它的输出为:
Thread-2玩家准备就绪
Thread-4玩家准备就绪
Thread-3玩家准备就绪
Thread-1玩家准备就绪
Thread-0玩家准备就绪
Thread-0玩家选择英雄
Thread-2玩家选择英雄
Thread-3玩家选择英雄
Thread-4玩家选择英雄
Thread-1玩家选择英雄
可以看到,当循环屏障内部的数减到0之前,所有的线程都阻塞在cyclicBarrier中
它的效果和下面使用countdown的组合方法一样:
CountDownLatch countDownLatch=new CountDownLatch(5);
for(int i=0;i<10;i++){
new Thread(()->{
try{
Thread.sleep(new Double(Math.random()*3000).longValue());
System.out.println(Thread.currentThread().getName()+"玩家准备就绪");
countDownLatch.countDown();//计数点
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"玩家选择英雄");
}catch (InterruptedException e){
e.printStackTrace();
}
}).start();
}
至于它为什么叫“循环”屏障,这是因为它内部的数字在减到0之后是可以恢复到原来的,例如,如果我们参数依然保持是5,但是创建10个线程时:
Thread-4玩家准备就绪
Thread-5玩家准备就绪
Thread-2玩家准备就绪
Thread-1玩家准备就绪
Thread-3玩家准备就绪
Thread-3玩家选择英雄
Thread-4玩家选择英雄
Thread-5玩家选择英雄
Thread-2玩家选择英雄
Thread-1玩家选择英雄
Thread-0玩家准备就绪
Thread-6玩家准备就绪
Thread-7玩家准备就绪
Thread-8玩家准备就绪
Thread-9玩家准备就绪
Thread-9玩家选择英雄
Thread-0玩家选择英雄
Thread-6玩家选择英雄
Thread-7玩家选择英雄
Thread-8玩家选择英雄