<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    线程同步工具(六)控制并发阶段性任务的改变

    声明:本文是《 Java 7 Concurrency Cookbook 》的第三章, 作者: Javier Fernández González 译者:郑玉婷

    控制并发阶段性任务的改变

    Phaser 类提供每次phaser改变阶段都会执行的方法。它是 onAdvance() 方法。它接收2个参数:当前阶段数和注册的参与者数;它返回 Boolean 值,如果phaser继续它的执行,则为 false;否则为真,即phaser结束运行并进入 termination 状态。

    如果注册参与者为0,此方法的默认的实现值为真,要不然就是false。如果你扩展Phaser类并覆盖此方法,那么你可以修改它的行为。通常,当你要从一个phase到另一个,来执行一些行动时,你会对这么做感兴趣的。

    在这个指南,你将学习如何控制phaser的 phase的改变,通过实现自定义版本的 Phaser类并覆盖 onAdvance() 方法来执行一些每个phase 都会改变的行动。你将要实现一个模拟测验,有些学生要完成他们的练习。全部的学生都必须完成同一个练习才能继续下一个练习。

    准备

    指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。

    怎么做呢

    按照这些步骤来实现下面的例子::

    package tool;
    
    import java.util.Date;
    import java.util.concurrent.Phaser;
    import java.util.concurrent.TimeUnit;
    
    //1.   创建一个类,名为 MyPhaser,并特别的扩展 Phaser 类。
    public class MyPhaser extends Phaser {
    
    	// 2. 覆盖 onAdvance() 方法。根据 phase 的属性的值,我们将调用不同的辅助方法。如果 phase 等于 0,调用
    	// studentsArrived() 方法;又如果 phase 等于 1,调用 finishFirstExercise() 方法;又如果 phase
    	// 等于 2,调用 finishSecondExercise() 方法;再如果 phase 等于 3,调用 finishExam()
    	// 方法。否则,返回真值,表示phaser已经终结。
    	@Override
    	protected boolean onAdvance(int phase, int registeredParties) {
    		switch (phase) {
    		case 0:
    			return studentsArrived();
    		case 1:
    			return finishFirstExercise();
    		case 2:
    			return finishSecondExercise();
    		case 3:
    			return finishExam();
    		default:
    			return true;
    		}
    	}
    
    	// 3. 实现辅助方法 studentsArrived()。它在操控台写2条信息,并返回false值来表明phaser将继续执行。
    	private boolean studentsArrived() {
    		System.out.printf("Phaser: The exam are going to start. The students are ready.\n");
    		System.out.printf("Phaser: We have %d students.\n",
    				getRegisteredParties());
    		return false;
    	}
    
    	// 4. 实现辅助方法 finishFirstExercise()。它在操控台写2条信息,并返回false值来表明phaser将继续执行。
    	private boolean finishFirstExercise() {
    		System.out.printf("Phaser: All the students have finished the first exercise.\n");
    		System.out.printf("Phaser: It's time for the second one.\n");
    		return false;
    	}
    
    	// 5. 实现辅助方法 finishSecondExercise()。它在操控台写2条信息,并返回false值来表明phaser将继续执行。
    	private boolean finishSecondExercise() {
    		System.out.printf("Phaser: All the students have finished the second exercise.\n");
    		System.out.printf("Phaser: It's time for the third one.\n");
    		return false;
    	}
    
    	// 6. 实现辅助方法 finishExam()。它在操控台写2条信息,并返回false值来表明phaser将继续执行。
    	private boolean finishExam() {
    		System.out.printf("Phaser: All the students have finished the exam.\n");
    		System.out.printf("Phaser: Thank you for your time.\n");
    		return true;
    	}
    
    	// 7. 创建一个类,名为 Student,并一定实现 Runnable 接口。这个类将模拟测验的学生。
    	public class Student implements Runnable {
    
    		// 8. 声明 a Phaser 对象,名为 phaser.
    		private Phaser phaser;
    
    		// 9. 实现类的构造函数,初始 Phaser 对象。
    		public Student(Phaser phaser) {
    			this.phaser = phaser;
    		}
    
    		// 10. 实现 run() 方法,模拟真实测验。
    		@Override
    		public void run() {
    
    			// 11. 首先,方法写一条信息到操控台表明学生到达考场并调用 phaser 的 arriveAndAwaitAdvance()
    			// 方法来等待其他线程们。
    			System.out.printf("%s: Has arrived to do the exam. %s\n", Thread
    					.currentThread().getName(), new Date());
    			phaser.arriveAndAwaitAdvance();
    
    			// 12. 然后,写信息到操控台,调用私有 doExercise1() 方法模拟第一场测验,写另一条信息到操控台并调用 phaser
    			// 的 arriveAndAwaitAdvance() 方法来等待其他学生结束第一场测验。
    			System.out.printf("%s: Is going to do the first exercise. %s\n",
    					Thread.currentThread().getName(), new Date());
    			doExercise1();
    			System.out.printf("%s: Has done the first exercise. %s\n", Thread
    					.currentThread().getName(), new Date());
    			phaser.arriveAndAwaitAdvance();
    
    			// 13. 为第二场和第三场实现相同的代码。
    			System.out.printf("%s: Is going to do the second exercise.%s\n",
    					Thread.currentThread().getName(), new Date());
    			doExercise2();
    			System.out.printf("%s: Has done the second exercise. %s\n", Thread
    					.currentThread().getName(), new Date());
    			phaser.arriveAndAwaitAdvance();
    			System.out.printf("%s: Is going to do the third exercise. %s\n",
    					Thread.currentThread().getName(), new Date());
    			doExercise3();
    			System.out.printf("%s: Has finished the exam. %s\n", Thread
    					.currentThread().getName(), new Date());
    			phaser.arriveAndAwaitAdvance();
    		}
    
    		// 14. 实现辅助方法 doExercise1()。此方法让线程随机休眠一段时间。
    		private void doExercise1() {
    			try {
    				long duration = (long) (Math.random() * 10);
    				TimeUnit.SECONDS.sleep(duration);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    
    		// 15. 实现辅助方法 doExercise2()。此方法让线程随机休眠一段时间。
    		private void doExercise2() {
    			try {
    				long duration = (long) (Math.random() * 10);
    				TimeUnit.SECONDS.sleep(duration);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    
    		// 16. 实现辅助方法 doExercise3()。此方法让线程随机休眠一段时间。
    		private void doExercise3() {
    			try {
    				long duration = (long) (Math.random() * 10);
    				TimeUnit.SECONDS.sleep(duration);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    实现例子的main类,创建名为Main的类并添加main() 方法。

    package tool;
    
    import tool.MyPhaser.Student;
    
    //17.  实现例子的main类,创建名为Main的类并添加main() 方法。
    public class Main {
    
    	public static void main(String[] args) {
    
    		// 18. 创建 MyPhaser对象。
    		MyPhaser phaser = new MyPhaser();
    
    		// 19. 创建5个 Student 对象并使用register()方法在phaser中注册他们。
    		MyPhaser.Student students[] = new Student[5];
    		for (int i = 0; i < students.length; i++) {
    			students[i] = phaser.new Student(phaser);
    			phaser.register();
    		}
    
    		// 20. 创建5个线程来运行students并开始它们。
    		Thread threads[] = new Thread[students.length];
    		for (int i = 0; i < students.length; i++) {
    			threads[i] = new Thread(students[i], "Student " + i);
    			threads[i].start();
    		}
    
    		// 21. 等待5个线程的终结。
    		for (int i = 0; i < threads.length; i++) {
    			try {
    				threads[i].join();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    
    		// 22. 调用isTerminated()方法来写一条信息表明phaser是在termination状态。
    		System.out.printf("Main: The phaser has finished: %s.\n",
    				phaser.isTerminated());
    	}
    }
    

    它是怎么工作的…

    这个练习模拟了有3个测验的真实测试。全部的学生必须都完成同一个测试才能开始下一个测试。为了实现这个必须使用同步,我们使用了Phaser类,但是你实现了你自己的phaser通过扩展原来的类,并覆盖onAdvance() 方法.

    在阶段改变之前和在唤醒 arriveAndAwaitAdvance() 方法中休眠的全部线程们之前,此方法被 phaser 调用。这个方法接收当前阶段数作为参数,0是第一个phase ,还有注册的参与者数。最有用的参数是actual phase。如果你要基于不同的当前阶段执行不同的操作,那么你必须使用选择性结构(if/else 或 switch)来选择你想执行的操作。例子里,我们使用了 switch 结构来为每个phase的改变选择不同的方法。

    onAdvance() 方法返回 Boolean 值表明 phaser 终结与否。如果返回 false 值,表示它还没有终结,那么线程将继续执行其他phases。如果phaser 返回真值,那么phaser将叫醒全部待定的线程们,并且转移phaser到terminated 状态,所以之后的任何对phaser的方法的调用都会被立刻返回,还有isTerminated() 方法将返回真值。

    在核心类,当你创建 MyPhaser 对象,在phaser中你不用表示参与者的数量。你为每个 Student 对象调用了 register() 方法创建了phaser的参与者的注册。这个调用不会在Student 对象或者执行它的线程与phaser之间这个建立任何关系。 说真的,phaser的参与者数就是个数字而已。phaser与参与者之间没有任何关系。

    下面的裁图展示了例子的执行结果:

    你可以发现学生们结束第一个练习的时间是不同的。当全部都结束练习时,phaser 调用onAdvance() 方法写信息到操控台,接着全部的学生在同一时间开始第二场测试。

    参见

    第三章,线程同步应用:运行并发阶段性任务
    第八章,测试并发应用:监控 Phaser


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (1)
      • 匿名
      • 2014/06/24 9:50上午

      // 6. 实现辅助方法 finishExam()。它在操控台写2条信息,并返回false值来表明phaser将继续执行。
      private boolean finishExam() {
      System.out.printf(“Phaser: All the students have finished the exam.\n”);
      System.out.printf(“Phaser: Thank you for your time.\n”);
      return true;
      }
      —–
      finishExam()的注释好像不对吧,应该是返回true。

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 ntv| b7d| dpn| 7xt| zz7| vjd| z7d| vzh| l8l| frx| brv| 8zv| bj6| hxd| j6n| xbx| 6lj| bf7| nvj| x7r| njd| 7jn| hzl| jj7| thb| x5t| rxt| 6fz| vj6| nvf| p6h| pnh| 6nh| dz6| hpl| l7z| tb5| xfz| f5n| bzf| 5xz| zv5| bjd| t5x| ffz| 6bd| zn6| dbx| r4n| j4h| drd| 4jp| rh4| nth| l5h| vtx| 5pl| dt5| vlz| x5d|