Java 并发 API 提供的其中一个最复杂且强大的功能是使用 Phaser 类来执行同步phased任务。当有些任务可以分成步骤执行时,此机制是很有用的。Phaser类提供的同步线程机制是在每个步骤的末端, 所以全部的线程都完成第一步后,才能开始执行第二步。
在这个指南,你将学习如何从Phaser类获取其状态信息。 准备
指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。
怎么做呢…
按照这些步骤来实现下面的例子:
01 //1. 创建一个类,名为 Task ,实现 Runnable 接口. 02 public class Task implements Runnable { 03 04 //2. 声明一个私有 int 属性,名为 time。 05 private int time; 06 07 //3. 声明私有 Phaser 属性,名为 phaser. 08 private Phaser phaser; 09 10 //4. 实现类的构造函数,初始其属性值。 11 public Task(int time, Phaser phaser) { 12 this.time=time; 13 this.phaser=phaser; 14 } 15 16 //5. 实现 run() 方法。首先,使用 arrive() 方法指示 phaser 属性任务开始执行了。 17 @Override 18 public void run() { 19 20 phaser.arrive(); 21 22 //6. 写信息到操控台表明阶段一开始,把线程放入休眠几秒,使用time属性来表明,再写信息到操控台表明阶段一结束,并使用 phaser 属性的 arriveAndAwaitAdvance() 方法来与剩下的任务同步。 23 System.out.printf("%s: Entering phase 1.\n",Thread. currentThread().getName()); 24 try { 25 TimeUnit.SECONDS.sleep(time); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 System.out.printf("%s: Finishing phase 1.\n",Thread. currentThread().getName()); 30 phaser.arriveAndAwaitAdvance(); 31 32 //7. 为第二和第三阶段重复第一阶段的行为。在第三阶段的末端使用 arriveAndDeregister()方法代替 arriveAndAwaitAdvance() 方法。 33 System.out.printf("%s: Entering phase 2.\n",Thread. currentThread().getName()); 34 try { 35 TimeUnit.SECONDS.sleep(time); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 System.out.printf("%s: Finishing phase 2.\n",Thread. currentThread().getName()); 40 phaser.arriveAndAwaitAdvance(); 41 42 System.out.printf("%s: Entering phase 3.\n",Thread. currentThread().getName()); 43 try { 44 TimeUnit.SECONDS.sleep(time); 45 } catch (InterruptedException e) { 46 e.printStackTrace(); 47 } 48 System.out.printf("%s: Finishing phase 3.\n",Thread. currentThread().getName()); 49 50 phaser.arriveAndDeregister(); 51 52 //8. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。 53 public class Main { 54 55 public static void main(String[] args) throws Exception { 56 57 //9. 创建新的有3个参与者的 Phaser 对象,名为 phaser。 58 Phaser phaser=new Phaser(3); 59 60 //10. 创建并运行3个线程来执行3个task对象。 61 for (int i=0; i<3; i++) { 62 Task task=new Task(i+1, phaser); 63 Thread thread=new Thread(task); 64 thread.start(); 65 } 66 67 //11.创建迭代10次的for循环,来学关于phaser对象的信息。 68 for (int i=0; i<10; i++) { 69 70 //12. 写关于 registered parties 的信息,phaser的phase,到达的parties, 和未到达的parties 的信息。 71 System.out.printf("********************\n"); 72 System.out.printf("Main: Phaser Log\n"); 73 System.out.printf("Main: Phaser: Phase: %d\n",phaser.getPhase()); 74 System.out.printf("Main: Phaser: Registered Parties:%d\n",phaser.getRegisteredParties()); 75 System.out.printf("Main: Phaser: Arrived Parties:%d\n",phaser.getArrivedParties()); 76 System.out.printf("Main: Phaser: Unarrived Parties:%d\n",phaser.getUnarrivedParties()); 77 System.out.printf("********************\n"); 78 79 //13. 让线程休眠1秒,并合上类的循环。 80 TimeUnit.SECONDS.sleep(1); 81 } 82 } 83 }它是如何工作的…
在这个指南,我们在 Task 类实现了 phased 任务。此 phased 任务有3个phases,并使用Phaser接口来与其他Task对象同步。当这些任务正在执行他们的phases时候,主类运行3个任务并打印关于phaser对象的状态信息到操控台。 我们使用以下的方法来获取phaser对象的状态:
getPhase():此方法返回phaser 任务的 actual phasegetRegisteredParties(): 此方法返回使用phaser对象作为同步机制的任务数getArrivedParties(): 此方法返回已经到达actual phase末端的任务数getUnarrivedParties(): 此方法返回还没到达actual phase末端的任务数以下的裁图展示了项目的部分输出: