阶段并发任务中控制阶段变化

Java 9并发编程指南 目录

阶段并发任务中控制阶段变化

onAdvance()是Phaser类提供的方法,用来在每次执行时phaser变化阶段。它接收两个参数:当前阶段的数量和注册参与者的数量。如果Phaser继续执行则返回布尔值false,或者Phaser已经结束并且必须进入终止状态时返回true。

如果注册参与者的数量为零,此方法的默认实现返回true,否则为false。但是可以通过继承Phaser类以及重写此方法修改这个特性。正常情况下,当需要执行一些活动从一个阶段到下一个阶段时,重写此方法会很有趣。

在本节中,通过重写Phaser类的onAdvance()方法在每个阶段变化中执行活动,学习如何控制阶段中的变化。本范例模拟一场考试,学生需要完成三个测试,所有学生必须完成一个测试之后才能进行下一个。

准备工作

本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。

实现过程

通过如下步骤完成范例:

  1. 创建名为MyPhaser的类,继承Phaser类:

    public class MyPhaser extends Phaser{
    
  2. 重写onAdvance()方法。根据phase属性值,掉哦那个不同的附属方法。如果phase属性值等于0,调用studentsArrived()方法。如果phase属性值等于1,调用finishFirstExercise()方法。如果phase属性值等于2,调用finishSecondExercise()方法。最后,如果phase属性值等于3,调用finishExam()方法。否则,返回true表明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(),输出两条日志信息到控制台并且返回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(),输出两条信息到控制台并且返回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(),输出两条信息到控制台并且返回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(),输出两条信息到控制台并且返回true表明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 false;
    	}
    
  7. 创建名为Student的类实现其Runnable接口,此类用来模拟考试中的学生:

    public class Student implements Runnable {
    
  8. 定义名为phaser的Phaser属性:

    	private Phaser phaser;
    
  9. 实现类构造函数,初始化Phaser对象:

    	public Student(Phaser phaser) {
    		this.phaser = phaser;
    	}
    
  10. 实现run()方法,模拟考试实现:

    	@Override
    	public void run() {
    
  11. 首先,方法输出指明一个学生已经进入考场的信息到控制台,并且调用phaser的arrvieAndAwaitAdvance()方法等待其它线程:

    		System.out.printf("%s : Has arrived to do the exam. %s\n", Thread.currentThread().getName(), new Date());
    		phaser.arriveAndAwaitAdvance();
    
  12. 然后,输出信息到控制台,调用doExercise1()方法模拟考试第一个测试的实现。接下来,输出另一条信息到控制台,调用phaser的arrvieAndAwaitAdvance()方法等待完成第一个测试的其他学生:

    		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();
    		}
    	}
    
  17. 实现范例的主类,创建一个包含main()方法的Main类:

    public class Main {
    	public static void main(String[] args) {
    
  18. 创建MyPhaser对象:

    		MyPhaser phaser = new MyPhaser();
    
  19. 创建五个Student对象,使用register()方法注册到phaser属性中:

    		Student students[] = new Student[5];
    		for ( int i = 0 ; i < students.length ; i ++) {
    			students[i] = new Student(phaser);
    			phaser.register();
    		}
    
  20. 创建五个线程,开始执行:

    		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. 等待五个线程结束:

    		for ( int i = 0 ; i < students.length ; i ++) {
    			try {
    				threads[i].join();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    
  22. 使用isTerminated()方法,输出展示phaser处于终止状态的信息到控制台:

    		System.out.printf("Main : The phaser has finished : %s.\n", phaser.isTerminated());
    

工作原理

本范例模拟包括三个测试的考试实现。所有学生必须现完成一个测试才能开始下一个。为实现并发要求,我们使用Phaser类,然而这种情况下,需要通过继承原始类重写onAdvance()方法,定制phaser对象。

在阶段变化以及唤醒arrvieAndAwaitAdvance()方法中休眠的所有线程之前,Phaser调用此方法。结束一个阶段的最后一个线程调用此方法,以此作为arrvieAndAwaitAdvance()方法的部分代码。这个方法传递实际阶段的数量作为-0表示第一个阶段,以及注册参与者的数量为参数。实际阶段是最有用的参数,如果依赖实际阶段执行不同的操作,需要使用选择结构(if…else或则switch)确定想要执行的操作。本范例中,我们使用switch结构为每个阶段变化选择不同的方法。

onAdvance()方法返回表明phaser是否终止的布尔值,如果phaser返回false,表示它未终止,线程将继续其他阶段的执行。如果phaser返回true,phaser依然唤醒等待线程,但将phaser置为终止状态。借此未来所有被调用的phaser方法将立即返回,isTerminated()方法返回true。

在Main类中,当创建Phaser对象时,不用明确阶段中的参与者数量,为每个Student对象调用register()方法即可注册成phaser中的参与者。Student对象或者执行对象的线程并没有因为方法调用和phaser建立关联,阶段的参与者数量只是一个数字,phaser和参与者之间没有联系。

下图显示本范例在控制台输出的执行结果:

pics/03_05.jpg

可以看到学生在不同的时间内完成第一个测试,当所有学生结束第一个测试时,phaser调用onAdvance()方法在控制台输出信息,然后所有学生在同时开始第二个测试。

更多关注

  • 本章“运行阶段并发任务”小节。
  • 第九章“测试并发应用”中的“监控Phaser类”小节。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值