• 多线程工具类-Phaser(阶段器)使用案例


    Phaser表示“阶段器”,用来解决控制多个线程分阶段共同完成任务的情景问题。

    其作用相比CountDownLatch和CyclicBarrier更加灵活;

    例如有这样的一个题目:5个学生一起参加考试,一共有三道题,要求所有学生到齐才能开始考试,全部同学都做完第一题,学生才能继续做第二题,全部学生做完了第二题,才能做第三题,所有学生都做完的第三题,考试才结束。

    分析这个题目:这是一个多线程(5个学生)分阶段问题(考试考试、第一题做完、第二题做完、第三题做完),所以很适合用Phaser解决这个问题。

    实现代码

    1、扩展并自定义阶段器行为

    import java.util.concurrent.Phaser;
     
    /***
     *  下面说说Phaser的高级用法,在Phaser内有2个重要状态,分别是phase和party。
     *  phase就是阶段,初值为0,当所有的线程执行完本轮任务,同时开始下一轮任务时,
     *  意味着当前阶段已结束,进入到下一阶段,phase的值自动加1。party就是线程,
     *  party=4就意味着Phaser对象当前管理着4个线程。Phaser还有一个重要的方法经常需要被重载,
     *  那就是boolean onAdvance(int phase, int registeredParties)方法。此方法有2个作用:
     *  1、当每一个阶段执行完毕,此方法会被自动调用,因此,重载此方法写入的代码会在每个阶段执行完毕时执行,
     *  相当于CyclicBarrier的barrierAction。
     *  2、当此方法返回true时,意味着Phaser被终止,因此可以巧妙的设置此方法的返回值来终止所有线程。
     */
    public class MyPhaser extends Phaser {
    
        // 在每个阶段执行完成后回调的方法
        // phase 表示阶段
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            switch (phase) {
                case 0:
                    return studentArrived();
                case 1:
                    return done("第一题");
                case 2:
                    return done("第二题");
                case 3:
                    return done("第三题");
                default:
                    return true;
            }
        }
    
        private boolean studentArrived() {
            System.out.println("学生准备好了,学生人数:" + getRegisteredParties());
            return false;
        }
    
        private boolean done(String questionNum) {
            System.out.println("所有学生做完" + questionNum + ">>>");
            return false;
        }
    
    }
    

    2、定义资源类

    import java.util.concurrent.Phaser;
    import java.util.concurrent.TimeUnit;
     
    public class StudentTask implements Runnable {
    
        private Phaser phaser;
    
        public StudentTask(Phaser phaser) {
            this.phaser = phaser;
        }
    
        @Override
        public void run() {
            // 第一阶段
            System.out.println(Thread.currentThread().getName() + " >>>到达考试现场");
            phaser.arriveAndAwaitAdvance();  // 线程到达并且提前等待
    
            // 第二阶段
            System.out.println(Thread.currentThread().getName() + " >>>开始做第一题:时间流逝...");
            doExercise();  // 线程阻塞
            System.out.println(Thread.currentThread().getName() + " >>>做完第一题...");
            phaser.arriveAndAwaitAdvance();   // 线程到达并且提前等待
    
            // 第三阶段
            System.out.println(Thread.currentThread().getName() + " >>>开始做第二题:时间流逝...");
            doExercise();  // 线程阻塞
            System.out.println(Thread.currentThread().getName() + " >>>做完第二题...");
            phaser.arriveAndAwaitAdvance();   // 线程到达并且提前等待
    
            // 第四阶段
            System.out.println(Thread.currentThread().getName() + " >>>开始做第三题:时间流逝...");
            doExercise();  // 线程阻塞
            System.out.println(Thread.currentThread().getName() + " >>>做完第三题...");
            phaser.arriveAndAwaitAdvance();  // 线程到达并且提前等待
        }
    
        // 使当前线程随机一个阻塞时间
        private void doExercise() {
            long duration = (long) (Math.random() * 10);
            try {
                TimeUnit.SECONDS.sleep(duration);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    

    3、并发测试

    /**
     * 题目:5个学生参加考试,一共有三道题,要求所有学生到齐才能开始考试
     * ,全部做完第一题,才能继续做第二题,后面类似。
     * 
     * Phaser有phase和party两个重要状态,
     * phase表示阶段,party表示每个阶段的线程个数,
     * 只有每个线程都执行了phaser.arriveAndAwaitAdvance();
     * 才会进入下一个阶段,否则阻塞等待。
     * 例如题目中5个学生(线程)都条用phaser.arriveAndAwaitAdvance();就进入下一题
     */
    public class Main {
     
    	public static void main(String[] args) {
            // 阶段器
    		MyPhaser phaser = new MyPhaser();
    		// 创建5个任务的容器
            StudentTask[] studentTask = new StudentTask[5];
    		// 初始化5个任务
            for (int i = 0; i < studentTask.length; i++) {
    			studentTask[i] = new StudentTask(phaser);
                // 逐一将5个未到达party的线程添加到阶段器中管理
                phaser.register();
    		}
    		// 创建5个线程并开启任务
    		Thread[] threads = new Thread[studentTask.length];
    		for (int i = 0; i < studentTask.length; i++) {
    			threads[i] = new Thread(studentTask[i], "Student "+i);
    			threads[i].start();
    		}
    		//等待所有线程执行结束
    		for (int i = 0; i < studentTask.length; i++) {
    			try {
    				threads[i].join();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println("Phaser has finished:"+phaser.isTerminated());
    	}
    }
    

    4、结果

    结果
    Student 0 >>>到达考试现场
    Student 1 >>>到达考试现场
    Student 2 >>>到达考试现场
    Student 3 >>>到达考试现场
    Student 4 >>>到达考试现场
    学生准备好了,学生人数:5
    Student 4 >>>开始做第一题:时间流逝...
    Student 0 >>>开始做第一题:时间流逝...
    Student 2 >>>开始做第一题:时间流逝...
    Student 1 >>>开始做第一题:时间流逝...
    Student 3 >>>开始做第一题:时间流逝...
    Student 0 >>>做完第一题...
    Student 4 >>>做完第一题...
    Student 2 >>>做完第一题...
    Student 3 >>>做完第一题...
    Student 1 >>>做完第一题...
    所有学生做完第一题>>>
    Student 2 >>>开始做第二题:时间流逝...
    Student 1 >>>开始做第二题:时间流逝...
    Student 0 >>>开始做第二题:时间流逝...
    Student 3 >>>开始做第二题:时间流逝...
    Student 4 >>>开始做第二题:时间流逝...
    Student 3 >>>做完第二题...
    Student 0 >>>做完第二题...
    Student 2 >>>做完第二题...
    Student 4 >>>做完第二题...
    Student 1 >>>做完第二题...
    所有学生做完第二题>>>
    Student 1 >>>开始做第三题:时间流逝...
    Student 0 >>>开始做第三题:时间流逝...
    Student 0 >>>做完第三题...
    Student 3 >>>开始做第三题:时间流逝...
    Student 2 >>>开始做第三题:时间流逝...
    Student 4 >>>开始做第三题:时间流逝...
    Student 4 >>>做完第三题...
    Student 3 >>>做完第三题...
    Student 1 >>>做完第三题...
    Student 2 >>>做完第三题...
    所有学生做完第三题>>>
    Phaser has finished:false
    
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利
  • 相关阅读:
    十的次方——挖掘并非显而易见的观点与想法
    6-3-5式脑力接龙
    三个臭皮匠,顶上一个诸葛亮——在Google Ideathon上Design Thinking分享
    上瘾:如何打造习惯养成中的产品(投资篇)
    上瘾:如何打造习惯养成中的产品(奖励篇)
    上瘾:如何打造习惯养成中的产品(行动篇)
    上瘾:如何打造习惯养成中的产品(触发器篇)
    上瘾:如何打造习惯养成中的产品
    告别2013拥抱2014
    Design Thinking Workshop @ Agile Tour 2013 Shanghai
  • 原文地址:https://www.cnblogs.com/hhddd-1024/p/15259382.html
Copyright © 2020-2023  润新知