Java7 全新的線程同步機制 Phaser 理解

openkk 12年前發布 | 35K 次閱讀 Java Java開發

Java 7 引入了一個全新靈活的線程同步機制,名為 Phaser 。 如果你需要等待線程結束然后繼續執行其他任務,那么 Phaser 是一個好的選擇,接下來我們一步步來介紹 Phaser 的使用:

首先看下面的代碼:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Phaser;

public class PhaserExample {

 public static void main(String[] args) throws InterruptedException {

  List




   




     tasks = new ArrayList<>();

  for (int i = 0; i < 2; i++) {

   Runnable runnable = new Runnable() {
    @Override
    public void run() {
     int a = 0, b = 1;
     for (int i = 0; i < 2000000000; i++) {
      a = a + b;
      b = a - b;
     }
    }
   };

   tasks.add(runnable);

  }

  new PhaserExample().runTasks(tasks);

 }

 void runTasks(List




    




      tasks) throws InterruptedException {

  final Phaser phaser = new Phaser(1) {
   protected boolean onAdvance(int phase, int registeredParties) {
    return phase >= 1 || registeredParties == 0;
   }
  };

  for (final Runnable task : tasks) {
   phaser.register();
   new Thread() {
    public void run() {
     do {
      phaser.arriveAndAwaitAdvance();
      task.run();
     } while (!phaser.isTerminated());
    }
   }.start();
   Thread.sleep(500);
  }

  phaser.arriveAndDeregister();
 }

}




    




   

這個例子讓我們可以深入了解 Phaser 的使用,下面是對這個代碼的分析:

Line 8-27: main 方法創建了兩個 Runnable 任務
Line 29: 任務列表當作參數傳遞給 runTasks 方法

runTasks 方法實際使用了一個 Phaser 用于同步任務,使得每個任務在并行執行之前必須先到達屏障(Barrier)。列表中的任務執行了兩次,執行情況如下圖所示:

Java7 全新的線程同步機制 Phaser 理解

注意: "party" 是 Phaser 中的一個術語,相當于是線程的意思,當一個 party 到達,就是線程到達意思就是線程到了同步的屏障(Barrier)。
Line 35: create a Phaser that has one registered party (this means: at this time phaser expects one thread=party to arrive before it can start the execution cycle)
Line 36: implement the onAdvance-Method to explain that this task list is executed twice (done by: Line 37 says that it returns true if phase is equal or higher then 1)
Line 41: iterate over the list of tasks
Line 42: register this thread with the Phaser. Notice that a Phaser instance does not know the task instances. It's a simple counter of registered, unarrived and arrived parties, shared across participating threads. If two parties are registered then two parties must arrive at the phaser to be able to start the first cycle.
Line 46: tell the thread to wait at the barrier until the arrived parties equal the registered parties
Line 51: Just for demonstration purposes, this line delays execution. The original code snippet prints internal infos about the Phaser state to standard out.
Line 52: two tasks are registered, in total three parties are registered.
Line 54: deregister one party. This results in two registered parties and two arrived parties. This causes the threads waiting (Line 46) to execute the first cycle. (in fact the third party arrived while three were registered - but it does not make a difference)

原始的代碼 存放在 Git 倉庫中,執行的結果如下:
After phaser init -> Registered: 1 - Unarrived: 1 - Arrived: 0 - Phase: 0
After register -> Registered: 2 - Unarrived: 2 - Arrived: 0 - Phase: 0
After arrival -> Registered: 2 - Unarrived: 1 - Arrived: 1 - Phase: 0
After register -> Registered: 3 - Unarrived: 2 - Arrived: 1 - Phase: 0
After arrival -> Registered: 3 - Unarrived: 1 - Arrived: 2 - Phase: 0
Before main thread arrives and deregisters -> Registered: 3 - Unarrived: 1 - Arrived: 2 - Phase: 0
On advance -> Registered: 2 - Unarrived: 0 - Arrived: 2 - Phase: 0
After main thread arrived and deregistered -> Registered: 2 - Unarrived: 2 - Arrived: 0 - Phase: 1
Main thread will terminate ...
Thread-0:go  :Wed Dec 28 16:09:16 CET 2011
Thread-1:go  :Wed Dec 28 16:09:16 CET 2011
Thread-0:done:Wed Dec 28 16:09:20 CET 2011
Thread-1:done:Wed Dec 28 16:09:20 CET 2011
On advance -> Registered: 2 - Unarrived: 0 - Arrived: 2 - Phase: 1
Thread-0:go  :Wed Dec 28 16:09:20 CET 2011
Thread-1:go  :Wed Dec 28 16:09:20 CET 2011
Thread-1:done:Wed Dec 28 16:09:23 CET 2011
Thread-0:done:Wed Dec 28 16:09:23 CET 2011

Line 1: when the Phaser is initialized in line 35 of the code snippet then one party is registered and none arrived
Line 2: after the first thread is registered in Line 42 in the code example there are two registered parties and two unarrived parties. Since no thread reached the barrier yet, no party is arrived.
Line 3: the first thread arrives and waits at the barrier (line 46 in the code snippet)
Line 4: register the second thread, three registered, two unarrived, one arrived
Line 5: the second thread arrived at the barrier, hence two arrived now
Line 7: one party is deregistered in the code line 54 of the code example, therefore onAdvance-Method is called and returns false. This starts the first cycle since registered parties equals arrived parties (i.e. two). Phase 1 is started -> cycle one (see image mark 1)
Line 8: since all threads are notified and start their work, two parties are unarrived again, non arrived
Line 14: After the threads executed their tasks once they arrive again (code line 46) the onAdvance-Method is called, now the 2nd cycle is executed

英文鏈接:http://niklasschlimm.blogspot.com/2011/12/java-7-understanding-phaser.html

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!