前言:

哈喽,安瑞巴得,之前我们学习了多线程工具包java.util.concurrent里的一些工具类的使用场景及原理介绍(没看过的有兴趣可以回看一下),今天讲一下【Java多线程实战】系列的最后一篇Phaser的使用及原理,Phaser表示“阶段器”,用来解决控制多个线程分阶段共同完成任务的情景问题。Phaser相当于CountDownLatch和CyclicBarrier的进阶版本,功能跟强大,使用更灵活,可以满足我们更多的场景需求;

介绍:

Java 7 引入了一个全新灵活的线程同步机制,名为 Phaser 。如果你需要等待线程结束然后继续执行其他任务,那么 Phaser 是一个好的选择。他引入了新的Phaser的概念,我们可以将其看成一个一个的阶段,每个阶段都有需要执行的线程任务,任务执行完毕就进入下一个阶段。所以Phaser特别适合使用在重复执行或者重用的情况。

在之前讲CyclicBarrier我们举了一个点餐的case,所有小伙伴到齐之后才可以进行点餐,Phaser相当于CyclicBarrier的进阶版本,举个相似的例子就是:

当小伙伴们都到齐之后,进行点餐的时候,可以大家一起每人先点一杯喝的,全部点完喝的之后,进入下一个阶段每人在点一到热菜,点完热菜之后,每人在点一个甜点这不过分吧,然后进入下一阶段每人在点一份甜点,这就是Phaser阶段器;

代码示例(为了测试直观,代码我都写在一起了,大家写的时候记得每个方法要分开):

package com.wechat.wechatservice.controller.Executor;

import com.sun.tools.internal.jxc.SchemaGenerator;

import java.util.concurrent.Phaser;

/**
 * TODO
 *
 * @author taoze
 * @version 1.0
 * @date 6/28/21 2:33 PM
 */
public class PhaserTest extends Phaser {

    @Override
    protected boolean onAdvance(int phase, int registeredParties) {    //在每个阶段执行完成后回调的方法

        switch (phase) {
            case 0:
                return daoqi();
            case 1:
                return yingping();
            case 2:
                return zhucai();
            case 3:
                return tiandian();
            default:
                return true;
        }

    }

    private boolean tiandian() {
        System.out.println("甜点点完了!人数:" + getRegisteredParties());
        return false;
    }

    private boolean zhucai() {
        System.out.println("主菜点完了!人数:" + getRegisteredParties());
        return false;
    }

    private boolean yingping() {
        System.out.println("饮料点完咯!人数:" + getRegisteredParties());
        return false;
    }

    private boolean daoqi() {
        System.out.println("人都到齐咯,开始点菜,人数:" + getRegisteredParties());
        return false;
    }

    static class Runner implements Runnable {

        private Phaser phaser;

        public Runner(Phaser phaser) {
            this.phaser = phaser;
        }

        @Override
        public void run() {

            System.out.println("同学-"+Thread.currentThread().getName()+":到达");
            /**
             * 执行这个方法的话会等所有的选手都完成了之后再继续下面的方法
             */
            phaser.arriveAndAwaitAdvance();

            System.out.println("同学-"+Thread.currentThread().getName()+":点了一杯杨枝甘露");
            phaser.arriveAndAwaitAdvance();

            System.out.println("同学-"+Thread.currentThread().getName()+":点了一个鱼香肉丝");
            phaser.arriveAndAwaitAdvance();

            System.out.println("同学-"+Thread.currentThread().getName()+":点了一个巧克力圣代");
            phaser.arriveAndAwaitAdvance();

        }
    }

    public static void main(String[] args) {
        int runnerNum = 4;

        PhaserTest phaser = new PhaserTest();
        /**
         * 注册一次表示phaser维护的线程个数
         */
        phaser.register();
        for (int i = 0; i < runnerNum;  i++ ) {
            /**
             * 注册一次表示phaser维护的线程个数
             */
            phaser.register();
            new Thread(new Runner(phaser)).start();

        }
        /**
         * 后续阶段主线程就不参加了
         */
        phaser.arriveAndDeregister();
    }
}

执行结果:

解释: boolean onAdvance(int phase, int registeredParties)是Phaser的一个重要的方法经常需要被重载。此方法有2个作用:

  1. 当每一个阶段执行完毕,此方***被自动调用,因此,重载此方法写入的代码会在每个阶段执行完毕时执行,相当于CyclicBarrier的barrierAction。
  2. 当此方法返回true时,意味着Phaser被终止,因此可以巧妙的设置此方法的返回值来终止所有线程。

Phaser有phase和party两个重要状态:phase表示阶段,party表示每个阶段的线程个数,只有每个线程都执行了
phaser.arriveAndAwaitAdvance()才会进入下一个阶段,否则阻塞等待;

整洁成就卓越代码,细节之中只有天地