簡介
java7中引入了一種新的可重複使用的同步屏障,稱爲移相器Phaser。Phaser擁有與CyclicBarrier
和CountDownLatch
類似的功勞.
但是這個類提供了更加靈活的應用。CountDownLatch和CyclicBarrier都是隻適用於固定數量的參與者。移相器適用於可變數目的屏障,在這個意義上,可以在任何時間註冊新的參與者。並且在抵達屏障是可以註銷已經註冊的參與者。因此,註冊到同步移相器的參與者的數目可能會隨着時間的推移而變化。
如CyclicBarrier一樣,移相器可以重複使用,這意味着當前參與者到達移相器後,可以再一次註冊自己並等待另一次到達.
移相器的另一個重要特徵是:移相器可能是分層的,這允許你以樹形結構來安排移相器以減少競爭
簡單的使用
public class PhaserTest {
private final static Random RANDOM = new Random();
public static void main(String[] args) {
final Phaser phaser = new Phaser();
IntStream.rangeClosed(1,5).boxed().map(i->phaser).forEach(Task::new);
phaser.register();
phaser.arriveAndAwaitAdvance();//相當於CountDown
System.out.println("All of work are finished.");
}
static class Task extends Thread{
private final Phaser phaser;
Task(Phaser phaser) {
this.phaser = phaser;
phaser.register();//把自己加入計數器中
start();
}
@Override
public void run() {
System.out.println("The worker[ "+getName()+ " ]" +" is working.");
try {
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arriveAndAwaitAdvance();//自己完成,等待其他線程完成,相當於CyclicBarrier
}
}
}
結果:
The worker[ Thread-1 ] is working.
The worker[ Thread-2 ] is working.
The worker[ Thread-0 ] is working.
The worker[ Thread-4 ] is working.
The worker[ Thread-3 ] is working.
All of work are finished.
重複使用的例子
public class PhaserTest {
private final static Random RANDOM = new Random();
public static void main(String[] args) {
final Phaser phaser = new Phaser(5);
for (int i = 0; i < 6; i++) {
new Athletes(i,phaser).start();
}
}
static class Athletes extends Thread {
private final int no;
private final Phaser phaser;
Athletes(int no, Phaser phaser) {
this.no = no;
this.phaser = phaser;
}
@Override
public void run() {
try {
System.out.println(no + " start running.");
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
System.out.println(no + " end running.");
phaser.arriveAndAwaitAdvance();
System.out.println(no + " start bicycle.");
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
System.out.println(no + " end bicycle.");
phaser.arriveAndAwaitAdvance();
System.out.println(no + " start long jump.");
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
System.out.println(no + " end long jump.");
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
結果:
0 start running.
1 start running.
4 start running.
2 start running.
3 start running.
5 start running.
5 end running.
4 end running.
2 end running.
1 end running.
0 end running.
4 start bicycle.
......
動態減少
static class InjuredAthletes extends Thread {
private final int no;
private final Phaser phaser;
InjuredAthletes(int no, Phaser phaser) {
this.no = no;
this.phaser = phaser;
}
@Override
public void run() {
try {
sport(no, phaser, " start running.", " end running.");
sport(no, phaser, " start bicycle.", " end bicycle.");
System.out.println("I am injured.");
phaser.arriveAndDeregister();//動態減少
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Athletes extends Thread {
private final int no;
private final Phaser phaser;
Athletes(int no, Phaser phaser) {
this.no = no;
this.phaser = phaser;
}
@Override
public void run() {
try {
sport(no, phaser, " start running.", " end running.");
sport(no, phaser, " start bicycle.", " end bicycle.");
sport(no, phaser, " start long jump.", " end long jump.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void sport(int no, Phaser phaser, String s, String s2) throws InterruptedException {
System.out.println(no + s);
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
System.out.println(no + s2);
phaser.arriveAndAwaitAdvance();
}
API
重要API
註冊
public int register()
public int bulkRegister(int parties)
register
- 是註冊一個線程數,比較常用
bulkRegister
- 可以批量註冊
到達
public int arrive()
public int arriveAndDeregister()
public int arriveAndAwaitAdvance()
arrive
- 這個到達後,不會阻塞,相當於
countdown
機制
arriveAndAwaitAdvance
- 到達後會阻塞,相當於
CyclicBarrier
機制
arriveAndDeregister
- 當線程出現異常,不能正常到達時,可以調用該方法,
動態減少註冊數
舉例
public class PhaserTest {
private static final Random RANDOM = new Random();
public static void main(String[] args) throws InterruptedException {
final Phaser phaser = new Phaser(5);
for (int i = 0; i < 4; i++) {
new ArriveTask(i,phaser).start();
}
//等待全部任務進行完成
phaser.arriveAndAwaitAdvance();
System.out.println("The phase 1 work finish done.");
}
private static class ArriveTask extends Thread{
private final Phaser phaser;
private ArriveTask(int no,Phaser phaser) {
super(String.valueOf(no));
this.phaser = phaser;
}
@Override
public void run() {
System.out.println(getName() + " start working. ");
threadSleep();
System.out.println(getName() + " The phase one is running.");
phaser.arrive();
threadSleep();
System.out.println(getName() + " keep to other thing. ");
}
}
private static void threadSleep() {
try {
TimeUnit.SECONDS.sleep(RANDOM.nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
不再等待機制
protected boolean onAdvance(int phase, int registeredParties)
舉例
public class PhaserTest {
public static void main(String[] args) throws InterruptedException {
final Phaser phaser = new Phaser(2){
@Override
protected boolean onAdvance(int phase, int registeredParties) {
return true;
}
};
new OnAdvanceTask("Alex",phaser).start();
new OnAdvanceTask("Jack",phaser).start();
TimeUnit.SECONDS.sleep(3);
System.out.println(phaser.getArrivedParties());
System.out.println(phaser.getUnarrivedParties());
}
static class OnAdvanceTask extends Thread{
private final Phaser phaser;
OnAdvanceTask(String name, Phaser phaser) {
super(name);
this.phaser = phaser;
}
@Override
public void run() {
try {
sout();
TimeUnit.SECONDS.sleep(1);
if (getName().equals("Alex")){
System.out.println(phaser.isTerminated());
sout();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void sout() {
System.out.println(getName() + " I am start and the phase " + phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println(getName() + " I am end !");
}
}
}
結果:
Jack I am start and the phase 0
Alex I am start and the phase 0
Alex I am end !
Jack I am end !
true
Alex I am start and the phase -2147483647
Alex I am end !
2
0
- 默認情況,當別人調用arriveAndDeregister時,使註冊的數量減到0時,直接不會陷入阻塞,返回true,相當於銷燬掉
監控子線程任務
public int awaitAdvance(int phase)
public int awaitAdvanceInterruptibly(int phase) throws InterruptedException
- 相當於起到監控的作用
- 如果子線程還沒有執行完成,主線程就會阻塞
- 相較而言,可以不用增加註冊量
舉例
public static void main(String[] args) throws InterruptedException {
final Phaser phaser = new Phaser(4);
for (int i = 0; i < 4; i++) {
new AwaitAdvance(i,phaser).start();
}
//等待全部任務進行完成
phaser.awaitAdvance(phaser.getPhase());
System.out.println("The phase 1 work finish done.");
}
強制關閉
public void forceTermination()
public boolean isTerminated()
- 強制關閉phaser,但是
如果線程陷入阻塞,不會喚醒
調試API
獲取階段數
public final int getPhase()
- 返回當前相位數。 最大相位數爲Integer.MAX_VALUE
- 每增加一輪就會加一
舉例
public class PhaserTest {
public static void main(String[] args) {
final Phaser phaser = new Phaser(1);
System.out.println(phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println(phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println(phaser.getPhase());
phaser.arriveAndAwaitAdvance();
System.out.println(phaser.getPhase());
}
}
結果:
0
1
2
3
獲取註冊的數
public int getRegisteredParties()
- 獲得註冊的線程數,相當於Countdown初始的的計數器
- 可以動態更改
獲得到達和未到達的數目
public int getArrivedParties()
public int getUnarrivedParties()
getArrivedParties
- 獲得已經到達的線程數,和沒有到達的線程數
getUnarrivedParties
- 獲得沒有到達的線程數,和沒有到達的線程數
總結
- Phaser 可以通過
register
() 方法和arriveAndDeregister
() 方法,動態的增加或者減少註冊量 - 使用
arriveAndAwaitAdvance
,相當於CyclicBarrier
機制 - 使用
arrive
,相當於countdown
機制 - 可以利用
awaitAdvance
,讓主線程等待子線程全部完成任務