Java7:理解Phaser

轉自 http://hrps.me/2016/11/22/java-concurrent-phaser/

Java7引入一種稱為Phaser的靈活的線程同步機制。如果你需要所有線程到達之后,才繼續或者開始進行新的一組任務,Phaser是一個很好的選擇。
下面是代碼,及每一步的解釋。
感覺原代碼解釋的不好,我從新寫了個感覺更好理解。??

import java.util.concurrent.Phaser;

/**
 * Description:
 * User: Huang rp
 * Date: 16/11/23
 * Version: 1.0
 */
public class PhaserSamples {

    public static void main(String[] args) throws InterruptedException {
        new PhaserSamples().runTasks();

    }

    // 一共開幾場會
    private static final int PHASE_TO_TERMINATE = 2;
    // 初始參會人員數量
    private static final int INIT_PARTIES = 1;
    // 增加參會人員數量
    private static final int ADD_PARTIES = 5;
    // 每個會場限制參會者數量
    private static final int TASKS_PER_PHASER = 10;

    void runTasks() throws InterruptedException {
        final Phaser phaser = new Phaser(INIT_PARTIES) {
            // 所有人員到達完畢,開始會議;連續開PHASE_TO_TERMINATE - 1 場會議,會議結束(terminal)
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("第" + (phase + 1) + "場會議結束");
                return phase == (PHASE_TO_TERMINATE - 1) || registeredParties == 0;
            }
        };
        final Task tasks[] = new Task[ADD_PARTIES];

        System.out.println("會議開始準備,需要至少" + INIT_PARTIES + "人簽到, 共連續" + PHASE_TO_TERMINATE + "場會議,分會場數量" +
                (ADD_PARTIES % TASKS_PER_PHASER == 0 ? (ADD_PARTIES / TASKS_PER_PHASER) : (ADD_PARTIES / TASKS_PER_PHASER + 1)));
        System.out.println("Main準備參加第一場會議,開始簽到,共" + phaser.getRegisteredParties() + "人簽到");

        build(tasks, 0, tasks.length, phaser);
        for (int i = 0; i < tasks.length; i++) {
            final Thread thread = new Thread(tasks[i]);
            thread.start();
        }

        phaser.arriveAndDeregister();
        System.out.println("Main離開會場");
        // 準備下一場會議,如果沒有再到達會場,所有人都將等待
//        phaser.arriveAndAwaitAdvance();
//        System.out.println("Main休息準備下一場會議");
    }

    public static void build(Task[] tasks, int lo, int hi, Phaser ph) {
        if (hi - lo > TASKS_PER_PHASER) {
            for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
                int j = Math.min(i + TASKS_PER_PHASER, hi);
                build(tasks, i, j, new Phaser(ph));
            }
        } else {
            for (int i = lo; i < hi; ++i)
                tasks[i] = new Task(i + 1, ph);
        }
    }


    public static class Task implements Runnable {
        private final int id;
        private final Phaser phaser;

        public Task(int id, Phaser phaser) {
            this.id = id;
            this.phaser = phaser;
            this.phaser.register();
            System.out.println("參會人員" + id + "已經簽到,共" + phaser.getRegisteredParties() + "人簽到");
        }

        @Override
        public void run() {
            // 參加每一場會議
            while (!phaser.isTerminated()) {
                try {
                    // 簽到之后,走到會場
                    Thread.sleep(20 * id + 20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("參會人員" + this.id + "已經到達第" + (phaser.getPhase() + 1) + "場會議, 當前共有"
                        + phaser.getRegisteredParties() + " 人參會,"
                        + (phaser.getArrivedParties() + 1) + " 到達,"
                        + (phaser.getUnarrivedParties() - 1) + " 未到達");
                // 到達會場
                phaser.arriveAndAwaitAdvance();
            }
        }
    }
}

運行結果

會議開始準備,需要至少1人簽到, 共連續2場會議,分會場數量1
Main準備參加第一場會議,開始簽到,共1人簽到
參會人員1已經簽到,共2人簽到
參會人員2已經簽到,共3人簽到
參會人員3已經簽到,共4人簽到
參會人員4已經簽到,共5人簽到
參會人員5已經簽到,共6人簽到
Main離開會場
參會人員1已經到達第1場會議, 當前共有5 人參會,1 到達,4 未到達
參會人員2已經到達第1場會議, 當前共有5 人參會,2 到達,3 未到達
參會人員3已經到達第1場會議, 當前共有5 人參會,3 到達,2 未到達
參會人員4已經到達第1場會議, 當前共有5 人參會,4 到達,1 未到達
參會人員5已經到達第1場會議, 當前共有5 人參會,5 到達,0 未到達
第1場會議結束
參會人員1已經到達第2場會議, 當前共有5 人參會,1 到達,4 未到達
參會人員2已經到達第2場會議, 當前共有5 人參會,2 到達,3 未到達
參會人員3已經到達第2場會議, 當前共有5 人參會,3 到達,2 未到達
參會人員4已經到達第2場會議, 當前共有5 人參會,4 到達,1 未到達
參會人員5已經到達第2場會議, 當前共有5 人參會,5 到達,0 未到達
第2場會議結束

有幾點注意:
當簽到的人員數量等于到達會場人員數量,將立即開會,所以第一個人員到達會場會比最后一個簽到的晚才能保證所有人能參加會議。
可以一個會場容納所有人開會,將同一個phaser傳遞給所有的task;也可以維護一個層級關系,建立多個會場進行同一個會議,將所有參會人員平均分配到各個會場。
簽到之后,可以不用等待所有人到達會場可以立即離場,并且從簽到簿上抹掉簽名。
下一場會議開始之前,如果還有人員等待下一場會議,那么所有簽到的人都必須參加下一場。如果所有人都不等待,會議結束。
所有人員參加完指定數量的會議后,會議結束。

Phaser終止的兩種途徑,Phaser維護的線程執行完畢或者onAdvance()返回true
此外Phaser還能維護一個樹狀的層級關系,構造的時候new Phaser(parentPhaser),對于Task執行時間短的場景(競爭激烈),** TASKS_PER_PHASER**值設置較小,反之適當增大。

名詞解釋:

  • party 對應一個線程,數量可以通過register或者初始化new Phaser(num)的時候控制
  • arrive 對應一個party的狀態,初始時是unarrived,當調用arriveAndAwaitAdvance()或者 arriveAndDeregister()進入arrive狀態,可以通過getUnarrivedParties()獲取當前未到達的數量
  • register 注冊一個party,每一階段必須所有注冊的party都到達才能進入下一階段
  • phase 階段,當所有注冊的party都arrive之后,將會調用PhaseronAdvance()方法來判斷是否要進入下一階段
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容