JUC-线程协作-3-CyclicBarrier

CyclicBarrier 循环栅栏同样是一个线程协作工具,和 CountDownLatch 很像,都能阻塞一组线程

作用

当有大量线程相互配合,分别计算不同任务,并且需要最后统一汇总的时候,我们可以使用 CyclicBarrier,CyclicBarrier 可以构造一个集结点,当某一个线程执行完毕,它就会到集结点等待,直到所有线程都到了集结点,那么该栅栏就被撤销,所有线程再统一出发,继续执行剩下的任务.

常用方法

  • 构造函数,有两个参数,第一个是等待线程的数量,第二个是一个 Runnable 的实现
  • await(): 调用的线程进入阻塞状态等待

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Slf4j
public class CyclicBarrierDemo {

public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> log.info("所有线程都到了..."));

for (int i = 0; i < 5; i++) {
new Thread(new Task(i + 1, cyclicBarrier)).start();
}
}

@AllArgsConstructor
@Slf4j
static class Task implements Runnable{

private int id;

private CyclicBarrier cyclicBarrier;

@Override
public void run() {
log.info("当前线程正在执行,id:[{}]", id);
try {
Thread.sleep((long) (Math.random() * 10000));
cyclicBarrier.await();
log.info("所有线程都到了,继续执行,当前线程id:{}",id);
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}

}

控制台输出如下:

1
2
3
4
5
6
7
8
9
10
11
10:40:34.645 [Thread-1] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 当前线程正在执行,id:[2]
10:40:34.645 [Thread-0] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 当前线程正在执行,id:[1]
10:40:34.645 [Thread-2] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 当前线程正在执行,id:[3]
10:40:34.645 [Thread-3] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 当前线程正在执行,id:[4]
10:40:34.645 [Thread-4] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 当前线程正在执行,id:[5]
10:40:43.843 [Thread-4] INFO com.learning.java.cooperation.CyclicBarrierDemo - 所有线程都到了...
10:40:43.843 [Thread-4] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 所有线程都到了,继续执行,当前线程id:5
10:40:43.843 [Thread-2] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 所有线程都到了,继续执行,当前线程id:3
10:40:43.843 [Thread-0] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 所有线程都到了,继续执行,当前线程id:1
10:40:43.843 [Thread-1] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 所有线程都到了,继续执行,当前线程id:2
10:40:43.843 [Thread-3] INFO com.learning.java.cooperation.CyclicBarrierDemo$Task - 所有线程都到了,继续执行,当前线程id:4

首先声明一个数量是 5 的 CyclicBarrier, 然后新建5个线程,之后都调用 await() 方法,等到5个线程都调用 await() 方法之后,就会执行构造中传入的 Runnable 的实现, 然后所有线程唤醒,继续执行

对比 CountDownLatch

  1. 作用不同: CyclicBarrier 要等到固定数量的线程都到达了栅栏位置才能继续执行, CountDownLatch 只需要在计数器为0的时候就可以继续执行,也就是说 CountDownLatch 用于事件,而 CyclicBarrier 是用于线程的
  2. 可重用性不同: CountDownLatch 再倒数触发门闩打开之后就不能再重用了,而 CyclicBarrier 是可以重复使用的