【Java並發】 - Phaser使用(轉)__Java

來源:互聯網
上載者:User
原文連結 Overview Java 7的並發包中推出了Phaser,其功能跟CyclicBarrier和CountDownLatch有些重疊,但是提供了更靈活的用法,例如支援動態調整註冊任務的數量等。本文在Phaser內建的範例程式碼基礎上進行一下簡單的分析。

Glossary Registration  Phaser支援通過register()和bulkRegister(int parties)方法來動態調整註冊任務的數量,此外也支援通過其建構函式進行指定初始數量。在適當的時機,Phaser支援減少註冊任務的數量,例如 arriveAndDeregister()。單個Phaser執行個體允許的註冊任務數的上限是65535。

Arrival 正如Phaser類的名字所暗示,每個Phaser執行個體都會維護一個phase number,初始值為0。每當所有註冊的任務都到達Phaser時,phase number累加,並在超過Integer.MAX_VALUE後清零。arrive()和arriveAndDeregister()方法用於記錄到 達,arriveAndAwaitAdvance()方法用於記錄到達,並且等待其它未到達的任務。
Termination Phaser支援終止。Phaser終止之後,調用register()和bulkRegister(int parties)方法沒有任何效果,arriveAndAwaitAdvance()方法也會立即返回。觸發終止的時機是在protected boolean onAdvance(int phase, int registeredParties)方法返回時,如果該方法返回true,那麼Phaser會被終止。預設實現是在註冊任務數為0時返回true(即 return registeredParties == 0;)。此外,forceTermination()方法用於強制終止,isTerminated()方法用於判斷是否已經終止。
Tiering Phaser支援階層,即通過建構函式Phaser(Phaser parent)和Phaser(Phaser parent, int parties)構造一個樹形結構。這有助於減輕因在單個的Phaser上註冊過多的任務而導致的競爭,從而提升輸送量,代價是增加單個操作的開銷。

Sample Usage
Sample 1 在有些情境下,我們希望控制多個線程的啟動時機:例如在並發相關的單元測試中,有時需要控制線程的啟動時機,以期獲得最大程度的並發,通常我們會使用CountDownLatch,以下是使用Phaser的版本。
import java.util.concurrent.Phaser;    public class PhaserTest1 {        public static void main(String args[]) {          //          final int count = 5;          final Phaser phaser = new Phaser(count);          for(int i = 0; i < count; i++) {              System.out.println("starting thread, id: " + i);              final Thread thread = new Thread(new Task(i, phaser));              thread.start();          }      }            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;          }                    @Override          public void run() {              phaser.arriveAndAwaitAdvance();              System.out.println("in Task.run(), phase: " + phaser.getPhase() + ", id: " + this.id);          }      }  }  

 以上例子中,由於線程是在一個迴圈中start,因此start的時機有一定的間隔。本例中這些線程實際開始工作的時機是在所有的線程都調用了phaser.arriveAndAwaitAdvance()之後。

    此外,如果留心arriveAndAwaitAdvance()方法的簽名,會發現它並沒有拋出InterruptedException,實際上,即使 當前線程被中斷,arriveAndAwaitAdvance()方法也不會返回,而是繼續等待。如果在等待時希望可中斷,或者可逾時,那麼需要使用以下 方法:

awaitAdvance(arrive())  // 等效於arriveAndAwaitAdvance()  awaitAdvanceInterruptibly(int phase)  awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)  

Sample 2 有些時候我們希望只有在某些外部條件滿足時,才真正開始任務的執行,例如:

import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.util.concurrent.Phaser;    public class PhaserTest2 {        public static void main(String args[]) throws Exception {          //          final Phaser phaser = new Phaser(1);          for(int i = 0; i < 5; i++) {              phaser.register();              System.out.println("starting thread, id: " + i);              final Thread thread = new Thread(new Task(i, phaser));              thread.start();          }                    //          System.out.println("Press ENTER to continue");          BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));          reader.readLine();          phaser.arriveAndDeregister();      }            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;          }                    @Override          public void run() {              phaser.arriveAndAwaitAdvance();              System.out.println("in Task.run(), phase: " + phaser.getPhase() + ", id: " + this.id);          }      }  }  

 以上例子中,只有當使用者按下斷行符號之後,任務才真正開始執行。需要注意的是,arriveAndDeregister()方法不會被阻塞,並且返回到達時的phase number(arrive方法也是如此)。
Sample 3
import java.util.concurrent.Phaser;    public class PhaserTest3 {        public static void main(String args[]) throws Exception {          //          final int count = 5;          final int phaseToTerminate = 3;          final Phaser phaser = new Phaser(count) {              @Override              protected boolean onAdvance(int phase, int registeredParties) {                  System.out.println("====== " + phase + " ======");                  return phase >= phaseToTerminate || registeredParties == 0;              }          };                    //          for(int i = 0; i < count; i++) {              System.out.println("starting thread, id: " + i);              final Thread thread = new Thread(new Task(i, phaser));              thread.start();          }      }            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;          }                    @Override          public void run() {              do {                  try {                      Thread.sleep(500);                  } catch(InterruptedException e) {                      // NOP                  }                  System.out.println("in Task.run(), phase: " + phaser.getPhase() + ", id: " + this.id);                  phaser.arriveAndAwaitAdvance();              } while(!phaser.isTerminated());          }      }  }  

本例中的barrier action只是簡單地列印了一條資訊,此外在超過指定的迭代次數後終止了Phaser。
Sample 4 在Smaple 3的例子中,主線程在其它背景工作執行緒結束之前已經終止。如果希望主線程等待這些背景工作執行緒結束,除了使用Thread.join()之外,也可以嘗試以下的方式:
import java.util.concurrent.Phaser;    public class PhaserTest4 {        public static void main(String args[]) throws Exception {          //          final int count = 5;          final int phaseToTerminate = 3;          final Phaser phaser = new Phaser(count) {              @Override              protected boolean onAdvance(int phase, int registeredParties) {                  System.out.println("====== " + phase + " ======");                  return phase == phaseToTerminate || registeredParties == 0;              }          };                    //          for(int i = 0; i < count; i++) {              System.out.println("starting thread, id: " + i);              final Thread thread = new Thread(new Task(i, phaser));              thread.start();          }                    //          phaser.register();          while (!phaser.isTerminated()) {              phaser.arriveAndAwaitAdvance();          }          System.out.println("done");      }            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;          }                    @Override          public void run() {              while(!phaser.isTerminated()) {                  try {                      Thread.sleep(500);                  } catch(InterruptedException e) {                      // NOP                  }                  System.out.println("in Task.run(), phase: " + phaser.getPhase() + ", id: " + this.id);                  phaser.arriveAndAwaitAdvance();              }          }      }  }  

如果希望主線程在特定的phase結束之後終止,那麼可以在主線程中調用下述方法:
public static void awaitPhase(Phaser phaser, int phase) {      int p = phaser.register(); // assumes caller not already registered      while (p < phase) {          if (phaser.isTerminated()) {              break; // ... deal with unexpected

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.