Java 7: Understanding the Phaser

Java 7: Understanding the Phaser

Java 7 introduces a flexible thread synchronization mechanism called  Phaser. If you need to wait for threads to arrive before you can continue or start another set of tasks, then  Phaser is a good choice. Here is the listing, everything is explained step-by-step.
  1. import java.util.ArrayList;  
  2. import java.util.Date;  
  3. import java.util.List;  
  4. import java.util.concurrent.Phaser;  
  5.   
  6. public class PhaserExample {  
  7.   
  8.  public static void main(String[] args) throws InterruptedException {  
  9.   
  10.   List<runnable> tasks = new ArrayList<>();  
  11.   
  12.   for (int i = 0; i < 2; i++) {  
  13.    Runnable runnable = new Runnable() {  
  14.     @Override  
  15.     public void run() {  
  16.      int a = 0, b = 1;  
  17.      for (int i = 0; i < 2000000000; i++) {  
  18.       a = a + b;  
  19.       b = a - b;  
  20.      }  
  21.     }  
  22.    };  
  23.   
  24.    tasks.add(runnable);  
  25.   
  26.   }  
  27.   
  28.   new PhaserExample().runTasks(tasks);  
  29.   
  30.  }  
  31.   
  32.  void runTasks(List<runnable> tasks) throws InterruptedException {  
  33.   
  34.   final Phaser phaser = new Phaser(1) {  
  35.    protected boolean onAdvance(int phase, int registeredParties) {  
  36.     return phase >= 1 || registeredParties == 0;  
  37.    }  
  38.   };  
  39.   
  40.   for (final Runnable task : tasks) {  
  41.    phaser.register();  
  42.    new Thread() {  
  43.     public void run() {  
  44.      do {  
  45.       phaser.arriveAndAwaitAdvance();  
  46.       task.run();  
  47.      } while (!phaser.isTerminated());  
  48.     }  
  49.    }.start();  
  50.    Thread.sleep(500);  
  51.   }  
  52.   
  53.   phaser.arriveAndDeregister();  
  54.   
  55.  }  
  56.   
  57. }  
  58. </runnable></runnable>  

This example allows to learn a lot about the internals of a  Phaser. Let's go through the code:

Line 8-26: The  main-Method that creates two  Runnable tasks
Line 28: Task list is passed to the  runTasks-Method

The  runTasks-Method actually uses a  Phaser to synchronize the tasks in a way that each task in the list needs to arrive at the barrier before they are executed in parallel. The task list is executed twice. The first cycle is started when both threads arrived at the barrier (see image mark 1). The second cycle is started when both threads arrived at the barrier (see image mark 2).


Notice: "party" is a term in the  Phaser context that is equivalent to what we mean by a thread. When one party arrives, then one thread arrived at the synchronization barrier.

Line 34: 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 35: implement the  onAdvance-Method to explain that this task list is executed twice (done by: Line 36 says that it returns true if phase is equal or higher then 1)
Line 40: iterate over the list of tasks
Line 41: 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 45: tell the thread to wait at the barrier until the arrived parties equal the registered parties
Line 50: Just for demonstration purposes, this line delays execution. The  original code snippet prints internal infos about the Phaser state to standard out.
Line 51: two tasks are registered, in total three parties are registered.
Line 53: deregister one party. This results in two registered parties and two arrived parties. This causes the threads waiting (Line 45) to execute the first cycle. (in fact the third party arrived while three were registered - but it does not make a difference)

The original code snippet stored in my Git repository creates the following output:

  1. After phaser init -> Registered: 1 - Unarrived: 1 - Arrived: 0 - Phase: 0  
  2. After register -> Registered: 2 - Unarrived: 2 - Arrived: 0 - Phase: 0  
  3. After arrival -> Registered: 2 - Unarrived: 1 - Arrived: 1 - Phase: 0  
  4. After register -> Registered: 3 - Unarrived: 2 - Arrived: 1 - Phase: 0  
  5. After arrival -> Registered: 3 - Unarrived: 1 - Arrived: 2 - Phase: 0  
  6. Before main thread arrives and deregisters -> Registered: 3 - Unarrived: 1 - Arrived: 2 - Phase: 0  
  7. On advance -> Registered: 2 - Unarrived: 0 - Arrived: 2 - Phase: 0  
  8. After main thread arrived and deregistered -> Registered: 2 - Unarrived: 2 - Arrived: 0 - Phase: 1  
  9. Main thread will terminate ...  
  10. Thread-0:go  :Wed Dec 28 16:09:16 CET 2011  
  11. Thread-1:go  :Wed Dec 28 16:09:16 CET 2011  
  12. Thread-0:done:Wed Dec 28 16:09:20 CET 2011  
  13. Thread-1:done:Wed Dec 28 16:09:20 CET 2011  
  14. On advance -> Registered: 2 - Unarrived: 0 - Arrived: 2 - Phase: 1  
  15. Thread-0:go  :Wed Dec 28 16:09:20 CET 2011  
  16. Thread-1:go  :Wed Dec 28 16:09:20 CET 2011  
  17. Thread-1:done:Wed Dec 28 16:09:23 CET 2011  
  18. Thread-0:done:Wed Dec 28 16:09:23 CET 2011  

Line 1: when the  Phaser is initialized in line 34 of the code snippet then one party is registered and none arrived
Line 2: after the first thread is registered in Line 41 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 45 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 53 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 45) the  onAdvance-Method is called, now the 2nd cycle is executed

OK, go through it and look into my comments in  the original code snippet to learn more.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值