原创

Java并发编程(六)-Phaser

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyhkmm/article/details/84299103

phaser

        英文意思移相器,相位器,表示“阶段器”,用来解决控制多个线程分阶段共同完成任务的情景问题,其作用相比CountDownLatch和CyclicBarrier更加灵活。如100个人参加高考需要考四场考试,早上考语文,需要等100人都考完语文才能进行下午的数学,下午的数学都考完才能考明天的综合和英语。

操作方法

phaser(int parties)

        构造方法,与CountDownLatch一样,传入同步的线程数,也支持层次构造Phaser(Phaser parent)。

register()

        动态添加一个参与者。

bulkRegister(int Parties)

        动态添加多个参与者。

arriveAndDeregister()

        动态撤销线程在phaser的注册,通知phaser对象,该线程已经结束该阶段且不参与后面阶段。

isTerminated()

        当phaser没有参与同步的线程时(或者onAdvance返回true),phaser是终止态(如果phaser进入终止态arriveAndAwaitAdvance()和awaitAdvance()都会立即返回,不在等待)isTerminated返回true。

arrive()方法

        通知phaser该线程已经完成该阶段,但不等待其他线程。

arriveAndAwaitAdvance()

        类似await()方法,记录到达线程数,阻塞等待其他线程到达同步点后再继续执行。

awaitAdvance(int phase) /awaitAdvanceInterruptibly(int phase)

        传入阶段数,只有当前阶段等于phase阶段时才阻塞等待。后者如果线程在休眠被中断会抛出InterruptedException异常(phaser的其他方法对中断都不会抛出异常)。

onAdvance(int phase, int registeredParties)

        参数phase是阶段数,每经过一个阶段该数加1,registeredParties是当前参与的线程数。此方法有2个作用:1、当每一个阶段执行完毕,此方法会被自动调用,因此,重写此方法写入的代码会在每个阶段执行完毕时执行,相当于CyclicBarrier的barrierAction。2、当此方法返回true时,意味着Phaser被终止,因此可以巧妙的设置此方法的返回值来终止所有线程。例如:若此方法返回值为 phase>=3,其含义为当整个线程执行了4个阶段后,程序终止。

模拟学生参加高考的例子:

public class TestPhaser {
    public static void main(String[] args) {
        Phaser phaser=new MyPhaser();
        for(int i=1;i<=4;i++){
            phaser.register();
            new Thread(new StudentTask(phaser)).start();
        }
    }
}
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() + "--第一场语文开考...");
        doExam1();
        System.out.println(Thread.currentThread().getName() + "--第一场语文考完...");
        phaser.arriveAndAwaitAdvance();

        System.out.println(Thread.currentThread().getName() + "--第二场数学开考...");
        doExam2();
        System.out.println(Thread.currentThread().getName() + "--第二场数学考完...");
        phaser.arriveAndAwaitAdvance();

        System.out.println(Thread.currentThread().getName() + "--第三场综合开考...");
        doExam3();
        System.out.println(Thread.currentThread().getName() + "--第三场综合考完...");
        phaser.arriveAndAwaitAdvance();

        System.out.println(Thread.currentThread().getName() + "--第四场英语开考...");
        doExam4();
        System.out.println(Thread.currentThread().getName() + "--第四场英语考完...");
        phaser.arriveAndAwaitAdvance();
        System.out.println(Thread.currentThread().getName() + "--高考结束");
    }

    private void doExam1() {
        long duration = (long) (Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void doExam2() {
        long duration = (long) (Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void doExam3() {
        long duration = (long) (Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    private void doExam4() {
        long duration = (long) (Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class MyPhaser extends Phaser {
    
    @Override
    protected boolean onAdvance(int phase, int registeredParties) {	
        //在每个阶段执行完成后回调的方法
        switch (phase) {
            case 0:
                return studentArrived();
            case 1:
                return finishFirstExam();
            case 2:
                return finishSecondExam();
            case 3:
                return finishThreeExam();
            case 4:
                return finishFourExam();
            case 5:
                return finishExam();
            default:
                return true;
        }

    }
    private boolean studentArrived() {
        System.out.println("学生准备好了,学生人数:" + getRegisteredParties());
        return false;
    }
    private boolean finishFirstExam(){
        System.out.println("第一场语文所有学生考完");
        return false;
    }
    private boolean finishSecondExam(){
        System.out.println("第二场语文所有学生考完");
        return false;
    }
    private boolean finishThreeExam(){
        System.out.println("第三场语文所有学生考完");
        return false;
    }
    private boolean finishFourExam(){
        System.out.println("第四场英语所有学生考完");
        return false;
    }
    private boolean finishExam(){
        System.out.println("第三题所有学生做完,结束考试");
        return true;
    }
}

运行结果:

Thread-2--到达考试
Thread-3--到达考试
Thread-1--到达考试
Thread-0--到达考试
学生准备好了,学生人数:4
Thread-0--第一场语文开考...
Thread-2--第一场语文开考...
Thread-1--第一场语文开考...
Thread-3--第一场语文开考...
Thread-1--第一场语文考完...
Thread-3--第一场语文考完...
Thread-2--第一场语文考完...
Thread-0--第一场语文考完...
第一场语文所有学生考完
Thread-3--第二场数学开考...
Thread-1--第二场数学开考...
Thread-2--第二场数学开考...
Thread-0--第二场数学开考...
Thread-1--第二场数学考完...
Thread-3--第二场数学考完...
Thread-2--第二场数学考完...
Thread-0--第二场数学考完...
第二场语文所有学生考完
Thread-1--第三场综合开考...
Thread-3--第三场综合开考...
Thread-2--第三场综合开考...
Thread-0--第三场综合开考...
Thread-3--第三场综合考完...
Thread-2--第三场综合考完...
Thread-1--第三场综合考完...
Thread-0--第三场综合考完...
第三场语文所有学生考完
Thread-3--第四场英语开考...
Thread-1--第四场英语开考...
Thread-2--第四场英语开考...
Thread-0--第四场英语开考...
Thread-3--第四场英语考完...
Thread-0--第四场英语考完...
Thread-1--第四场英语考完...
Thread-2--第四场英语考完...
第四场英语所有学生考完
Thread-2--高考结束
Thread-0--高考结束
Thread-1--高考结束
Thread-3--高考结束
正文到此结束
Loading...