一、場景描述
有四個遊戲玩家玩遊戲,遊戲有三個關卡,每個關卡必須要所有玩家都到達後才能允許通過。其實這個場景裏的玩家中如果有玩家A先到了關卡1,他必須等到其他所有玩家都到達關卡1時才能通過,也就是說線程之間需要相互等待。這和CountDownLatch的應用場景有區別,CountDownLatch裏的線程是到了運行的目標後繼續幹自己的其他事情,而這裏的線程需要等待其他線程後才能繼續完成下面的工作。
二、CyclicBarrier介紹
CyclicBarrier 的字面意思是可循環使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續幹活。CyclicBarrier默認的構造方法是CyclicBarrier(int parties),其參數表示屏障攔截的線程數量,每個線程調用await方法告訴CyclicBarrier我已經到達了屏障,然後當前線程被阻塞。
CyclicBarrier類有兩個常用的構造方法:
1. CyclicBarrier(int parties)
這裏的parties也是一個計數器,例如,初始化時parties裏的計數是3,於是擁有該CyclicBarrier對象的線程當parties的計數爲3時就喚醒,注:這裏parties裏的計數在運行時當調用CyclicBarrier:await()時,計數就加1,一直加到初始的值
2. CyclicBarrier(int parties, Runnable barrierAction)
這裏的parties與上一個構造方法的解釋是一樣的,這裏需要解釋的是第二個入參(Runnable barrierAction),這個參數是一個實現Runnable接口的類的對象,也就是說當parties加到初始值時就出發barrierAction的內容。
代碼示例
package com.itmyhome;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 玩家類
* @author itmyhome
*
*/
class Player implements Runnable {
private CyclicBarrier cyclicBarrier;
private int id;
public Player(int id, CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
this.id = id;
}
@Override
public void run() {
try {
System.out.println("玩家" + id + "正在玩第一關...");
cyclicBarrier.await();
System.out.println("玩家" + id + "進入第二關...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public class CyclicBarrierTest {
public static void main(String[] args) {
// CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
CyclicBarrier cyclicBarrier = new CyclicBarrier(4,
new Runnable() {
@Override
public void run() {
System.out.println("所有玩家進入第二關!");
}
});
for (int i = 0; i < 4; i++) {
new Thread(new Player(i, cyclicBarrier)).start();
}
}
}
- 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
- 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
輸出結果:
玩家0正在玩第一關...
玩家3正在玩第一關...
玩家2正在玩第一關...
玩家1正在玩第一關...
所有玩家進入第二關!
玩家3進入第二關...
玩家1進入第二關...
玩家2進入第二關...
玩家0進入第二關...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
CyclicBarrier和CountDownLatch的區別
- CountDownLatch: 一個線程(或者多個), 等待另外N個線程完成某個事情之後才能執行。
- CyclicBarrier: N個線程相互等待,任何一個線程完成之前,所有的線程都必須等待。
- CountDownLatch的計數器只能使用一次。而CyclicBarrier的計數器可以使用reset() 方法重置。所以CyclicBarrier能處理更爲複雜的業務場景,比如如果計算髮生錯誤,可以重置計數器,並讓線程們重新執行一次。
- CountDownLatch:減計數方式,CyclicBarrier:加計數方式