0%

Java 同步和协作工具类(四):循环栅栏 CyclicBarrier

1. 怎样理解循环栅栏 CyclicBarrier

  • 相当于是一个栅栏,所有线程在到达该栅栏后都需要等待其他线程,等所有线程都到达后再一起通过
  • 它是循环的,可以用作重复的同步

2. 循环栅栏 CyclicBarrier 的使用场景

  • 循环栅栏 CyclicBarrier 特别适用于并行迭代计算
  • 每个线程负责一部分计算,然后在栅栏处等待其他线程完成,所有线程到齐后,交换数据和计算结果,再进行下一次迭代

3. 异常 BrokenBarrierException 的含义是

  • 循环栅栏 CyclicBarrierawait() 方法可能会抛出 BrokenBarrierException 异常
  • 这个异常的意思是:在 CyclicBarrier 中,参与的线程是互相影响的,只要其中一个线程在调用 await()被中断了,或者超时了,栅栏就会被破坏
  • 如果栅栏动作抛出了异常,栅栏也会被破坏
  • 栅栏被破坏后,所有在调用 await() 的线程就会退出,抛出 BrokenBarrierException

4. 写一个 CyclicBarrier 应用 Demo

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
34
35
36
37
38
39
40
41
42
43
44
45
46
//多个游客分别在集合点 A 和 B 同步
public class CyclicBarrierDemo {

static class Tourist extends Thread {
CyclicBarrier barrier;

public Tourist(CyclicBarrier barrier) {
this.barrier = barrier;
}

@Override
public void run() {
try {
//模拟先各自独立运行
Thread.sleep((int) (Math.random() * 1000));
//集合点 A
barrier.await();
System.out.println(this.getName() + " arrived A " + System.currentTimeMillis());
//集合后模拟再各自独立运行
Thread.sleep((int) (Math.random() * 1000));
//集合点 B
barrier.await();
System.out.println(this.getName() + " arrived B " + System.currentTimeMillis());
} catch(InterruptedException e) {
} catch(BrokenBarrierException e) {
}
}
}

public static void main(String[] args) {
int num = 3;
Tourist[] threads = new Tourist[num];

CyclicBarrier barrier = new CyclicBarrier(num, new Runnable() {
@Override
public void run() {
System.out.println("all arrived " + System.currentTimeMillis() + " executed by " + Thread.currentThread().getName());
}
});

for(int i=0; i<num; i++) {
threads[i] = new Tourist(barrier);
threads[i].start();
}
}
}

5. 循环栅栏 CyclicBarrier 和 倒计时门栓 CountDownLatch 的区别

  • 倒计时门栓 CountDownLatch 的参与线程是有不同角色的,有的负责倒计时,有的在等待倒计时变为 0,负责倒计时和等待倒计时的线程都可以有多个,用于不同角色线程间的同步
  • 循环栅栏 CyclicBarrier参与线程角色是一样的,用于同一角色线程间的协调一致
  • 倒计时门栓 CountDownLatch一次性的,循环栅栏 CyclicBarrier 是可以重复利用
-------------------- 本文结束感谢您的阅读 --------------------