Java併發包中的Phaser功能強大,靈活的同時,也很複雜,不容易理解,Phaser類似於CyclicBarrier和CountDownLatch。相比於CyclicBarrier, Phaser主要有以下特徵
- Phaser不但可以像CyclicBarrier一樣,可重複使用,而且能動態變更參與方數量數量,在 CyclicBarrier 中,在創建時,參與方數量是固定的。但是,在Phaser中,可以通過調用register()添加參與方,arriveAndDeregister()方法刪除參與方。
- 一個Phaser有一個相關的phrase號,從0開始。當所有註冊方都到達一個Phaser時,Phaser進入下一個phrase,phrase號遞增1。phrase號的最大值爲Integer.MAX_VALUE(private static final int MAX_PHASE= Integer.MAX_VALUE;)。最大值後,相位號以零爲起點重新開始。類似賽中的回合制。
- Phaser有一個終止狀態。在終止狀態下,所有在Phaser上調用的同步方法都會立即返回,而不需要等待預處理
- Phaser類的onAdvance()方法中寫代碼來指定一個phaser動作讓所有註冊方到達 phaser 時執行 phaser 動作。可以在個方法裏面返回true,讓Phaser不再執行。
用途:主要用於將一些併發任務分成若干個步驟
例如一個表的數據存儲在三個庫中,統計一個字段的數據,可以寫三個三個線程從三個庫中讀,在主線程中phaser.arriveAndAwaitAdvance()方法,等待三個線程執行完後,進行統計。
實例
我們用Phaser模擬一個跑步比賽,選手人數不定,比賽不分輪次,每一輪淘汰跑步時間超過一定時間的選手,直到最後一個勝出爲止。
Runner類繼承Thread類,代表每一個參賽者,,隨機生成一個1到5的整數,,用Thread.sleep()模擬參賽者跑步時長,每一輪都要等所有參賽者都到達後開始,當所有如果用時大於5秒,則淘汰。具體代碼:
import java.util.Random;
import java.util.concurrent.Phaser;
public class Runner extends Thread {
private final String name;
private final Phaser phaser;
private static Random rand = new Random();
public Runner(String name, Phaser phaser) {
this.name = name;
this.phaser = phaser;
}
@Override
public void run() {
while (!phaser.isTerminated()) {
try {
phaser.arriveAndAwaitAdvance();
if(phaser.getArrivedParties() == 1) {
System.out.println(String.format("%s win", name));
phaser.arriveAndDeregister();
return;
}
int sleepTime = rand.nextInt(5) + 1;
Thread.sleep(sleepTime * 1000);
System.out.println(String.format("%s run Time:%d", name, sleepTime));
if (sleepTime >= 5) {
phaser.arriveAndDeregister();
System.out.println(String.format("%s run Time:%d out", name, sleepTime));
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
RunnerTest類裏實現了Phaser類,重載了onAdvance()方法。
import java.util.concurrent.Phaser;
public class RunnerTest {
public static void main(String[] args) {
final Integer PERSON_COUNT = 3;
Phaser phaser = new Phaser() {
@Override
protected boolean onAdvance(int phase, int parties) {
System.out.println(String.format("%d arrive phase :%d", parties, phase));
if (parties == 1) {
return true;
}
System.out.println("------------------");
return false;
}
};
phaser.bulkRegister(PERSON_COUNT);
for (int i = 0; i < PERSON_COUNT; i++) {
Runner person = new Runner("Runner" + i, phaser);
person.start();
}
}
}
運行結果:
3 arrive phase :0
------------------
Runner1 run Time:1
Runner2 run Time:4
Runner0 run Time:5
2 arrive phase :1
------------------
Runner0 run Time:5 out
Runner1 run Time:4
Runner2 run Time:5
1 arrive phase :2
Runner2 run Time:5 out
Runner1 win