线程同步工具类CyclicBarrier

  • 1、CyclicBarrier的作用
  • 2、CyclicBarrier使用规则
  • 3、CyclicBarrier的Demo
  • 4、CyclicBarrier原理 (待补充)
  • 5、CyclicBarrier的实现 (待补充)

1、CyclicBarrier的作用

CyclicBarrier类也是java提供给我们同步任务的时候使用的,和CountDownLatch有点类似,都是控制任务执行的顺序的,不同的地方在于,CyclicBarrier可以让一个任务在执行的途中发生多次事件,而CountDownLatch却只能发生一次,就是在我们调用countDown方法的时候,这个事件触发以后,便会减少相应的锁存器上面的计数器,而当计数器为0的时候,哪些调用了await的任务便可以执行了,但是CyclicBarrier就不同了,CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞

2、CyclicBarrier的使用规则

CountDownLatch是一个同步的辅助类,允许一个或多个线程,等待其他一组线程完成操作,再继续执行。
CyclicBarrier是一个同步的辅助类,允许一组线程相互之间等待,达到一个共同点,再继续执行。

个人理解:CyclicBarrier:可看成是个障碍,所有的线程必须到齐后才能一起通过这个障碍
场景还原:以前公司组织户外拓展活动,帮助团队建设,其中最重要一个项目就是全体员工(包括女同事,BOSS)在完成其他项目时,到达一个高达四米的高墙没有任何抓点,要求所有人,一个不能少的越过高墙,才能继续进行其他项目。

3、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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* 探究CyclicBarrier的使用规则
* 模拟赛马游戏
* @author pengchengliu
*
*/
public class TestCycilcBarrier {
static final int FINISH_LINE = 100 ;
private List<Horse> mHorses = new ArrayList<Horse>() ;
private ExecutorService mExec = Executors.newCachedThreadPool() ;
private CyclicBarrier mCyclicBarrier ;

public TestCycilcBarrier (int horsesSize, int pause) {

// "栏栅动作",该动作为一个Runnable,这个Runnable在CyclicBarrier计数器变为0的时候执行。
mCyclicBarrier = new CyclicBarrier(horsesSize, new Runnable() {

@Override
public void run() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < FINISH_LINE; i++) {
stringBuilder.append("=");
}
System.out.println(stringBuilder);

for (Horse horse : mHorses) {
System.out.println(horse.tracks());
if (horse.getStrides() >= FINISH_LINE) {
System.out.println(horse + "won!");
mExec.shutdownNow();
return ;
}
}
try {
TimeUnit.MILLISECONDS.sleep(pause);
} catch (InterruptedException e) {
System.out.println("barrier-action sleep interrupted");
}

}
});

for (int i = 0; i < horsesSize; i++) {
Horse horse = new Horse(mCyclicBarrier);
mHorses.add(horse);
mExec.execute(horse);
}
}

public static void main(String[] args) {
int horsesSize = 10 ;
int pause = 200 ;

if (args.length > 0) {
Integer temp = new Integer(args[0]);
horsesSize = temp > 0 ? temp : horsesSize ;
}

if (args.length > 1) {
Integer temp = new Integer(args[1]);
pause = temp > 0 ? temp : pause ;
}

new TestCycilcBarrier(horsesSize, pause);
}
}
class Horse implements Runnable {
private static int sCounter = 0 ;
private final int ID = sCounter ++ ;
private int mStrides = 0 ;
private Random mRandom = new Random(47);
private static CyclicBarrier sBarrier ;

public Horse (CyclicBarrier cyclicBarrier) {
this.sBarrier = cyclicBarrier ;
}

@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
mStrides += mRandom.nextInt(5);
}
sBarrier.await();
}
} catch (InterruptedException e) {

} catch (BrokenBarrierException e) {
throw new RuntimeException(e) ;
}
}

public synchronized int getStrides () {
return mStrides ;
}

@Override
public String toString() {
return "Horse " + this.ID ;
}

public String tracks () {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < getStrides(); i++) {
stringBuffer.append("-");
}
stringBuffer.append(this.ID);
return stringBuffer.toString() ;
}
}

上述Demo运行起来的效果图,如下图所示:

赛马游戏

参考文献