三.多线程JUC篇-3.13 Phaser工具

1.前言

Phaser是JDK1.7提供的一种同步工具,是可重用的同步屏障,其功能类似于CyclicBarrier和CountDownLatch,但支持更灵活的用法:可以分阶段控制各个线程的行为,可以动态的创建也可以动态的注销。

2.用法

2.1 动态注册

public class MyPhaser7 {

    public static final Random random = new Random(System.currentTimeMillis());

    public static void main(String[] args) {
        final Phaser phaser = new Phaser();

        IntStream.rangeClosed(1, 5).boxed().map(i -> phaser).forEach(Task::new);

        phaser.register();
        phaser.arriveAndAwaitAdvance(); 
        System.out.println("All of workers finished the task.");
    }

    private static class Task extends Thread{

        private final Phaser phaser;

        public Task(Phaser phaser) {
            this.phaser = phaser;
            this.phaser.register();
            start();
        }

        @Override
        public void run() {
            System.out.println("The worker [" + getName() + "] is working..." );

            try {
                TimeUnit.SECONDS.sleep(random.nextInt(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            this.phaser.arriveAndAwaitAdvance();
        }
    }
}

----------------------------
The worker [Thread-0] is working...
The worker [Thread-2] is working...
The worker [Thread-4] is working...
The worker [Thread-1] is working...
The worker [Thread-3] is working...
All of workers finished the task.

2.2 多轮次

/**
 *    每个run()里面的phaser.arriveAndAwaitAdvance()都是一轮getPhase()的消费
 *    phaser的同一阶段arriveAndAwaitAdvance()全部执行完成才会执行下一阶段,即是相同的getPhase()值时
 */
public class MyPhaser8 {
    private static final Random random = new Random(System.currentTimeMillis());

    static class Athletes extends Thread {
        private final int num;
        private final Phaser phaser;

        public Athletes(int num, Phaser phaser) {
            this.num = num;
            this.phaser = phaser;
        }

        @Override
        public void run() {
            try {
                System.out.println(num + ": start running...");
                TimeUnit.SECONDS.sleep(random.nextInt(5));
                System.out.println(num + ": end running...");
                System.out.println(num + ": getPhase()=>" + phaser.getPhase());
                phaser.arriveAndAwaitAdvance();

                System.out.println(num + ": start bicycle...");
                TimeUnit.SECONDS.sleep(random.nextInt(5));
                System.out.println(num + ": end bicycle...");
                System.out.println(num + ": getPhase()=>" + phaser.getPhase());
                phaser.arriveAndAwaitAdvance();

                System.out.println(num + ": start long jump...");
                TimeUnit.SECONDS.sleep(random.nextInt(5));
                System.out.println(num + ": end long jump...");
                System.out.println(num + ": getPhase()=>" + phaser.getPhase());
                phaser.arriveAndAwaitAdvance();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        final Phaser phaser = new Phaser(5);

        for(int i = 0; i < 5; i++) {
            new Athletes(i, phaser).start();
        }
    }
}

2.3 可以动态的创建也可以动态的注销

/**
 *     Phaser可以动态的创建也可以动态的注销
 *     相当于一轮一轮的动作完成
 * 
 *    由于一个运动员受伤了, long jump这个动作没有完成,其它运动员都在等待他完成
 *    导致线程不能终止。 因此这个运动员需要phaser.arriveAndDeregister(),取消该相位注册让其他的相位
 *    不再等待
 */
public class MyPhaser9 {
    private static final Random random = new Random(System.currentTimeMillis());

    static class InjuredAthletes extends Thread {
        private final int num;
        private final Phaser phaser;

        public InjuredAthletes(int num, Phaser phaser) {
            this.num = num;
            this.phaser = phaser;
        }

        @Override
        public void run() {
            try {
                sport(phaser, num + ": start running...", num + ": end running...");

                sport(phaser, num + ": start bicycle...", num + ": end bicycle...");

//                System.out.println("Oh, shit. I am injured.");

                System.out.println("Oh shit, i am injured, i will exited.");
                phaser.arriveAndDeregister();//取消该相位注册让其他的相位不再等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Athletes extends Thread {
        private final int num;
        private final Phaser phaser;

        public Athletes(int num, Phaser phaser) {
            this.num = num;
            this.phaser = phaser;
        }

        @Override
        public void run() {
            try {
                sport(phaser, num + ": start running...", num + ": end running...");

                sport(phaser, num + ": start bicycle...", num + ": end bicycle...");

                sport(phaser, num + ": start long jump...", num + ": end long jump...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static void sport(Phaser phaser, String str1, String str2) throws InterruptedException {
        System.out.println(str1);
        TimeUnit.SECONDS.sleep(random.nextInt(5));
        System.out.println(str2);
        phaser.arriveAndAwaitAdvance();
    }

    public static void main(String[] args) {
        final Phaser phaser = new Phaser(5);

        for(int i = 1; i < 5; i++) {
            new Athletes(i, phaser).start();
        }

        new InjuredAthletes(5, phaser).start();
    }
}

2.4 arriveAndAwaitAdvance

报告已到达,且要求所有的parties到达才可以继续运行,否则阻塞等待

public class MyPhaser {
    public static void main(String[] args) {
        final Phaser phaser = new Phaser(3); //声明了三个parities
        new Thread(phaser::arriveAndAwaitAdvance).start(); 

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("registered parties: " + phaser.getRegisteredParties());

        System.out.println("arrived parties: " + phaser.getArrivedParties());
        System.out.println("unarrived parties: " + phaser.getUnarrivedParties());
		
		//现在只有一个parties到达,需要等待,所以主线程会永远等待下去
    }
}

---------------------
registered parties: 3
arrived parties: 1
unarrived parties: 2

2.5 arrive

报告已到达,立即返回,不阻塞等待(不需要检查所有的parties到达)
有一个场景:子任务分二个阶段,主线程只需要了解第一阶段的所有任务完成,不需要监控任务的第二阶段

public class MyPhaser3 {
    private final static Random random = new Random(System.currentTimeMillis());
    public static void main(String[] args) {
        Phaser phaser = new Phaser(5);
        for (int i = 0; i< 4; i++){
            new ArriveTask(phaser, i+1).start();
        }

        phaser.arriveAndAwaitAdvance();
        System.out.println("all task phase 1 end.");


    }

    private static class ArriveTask extends Thread{
        private final Phaser phaser;

        public ArriveTask(Phaser phaser, int no) {
            super(String.valueOf(no));
            this.phaser = phaser;
        }

        @Override
        public void run() {
            System.out.println(getName() + " start work...");

            mysleep();
            this.phaser.arrive();
            System.out.println(getName() + " phase 1 end.");

            mysleep();
            System.out.println(getName() + " phase 2 end.");
        }
    }

    private static void mysleep(){
        try {
            TimeUnit.SECONDS.sleep(random.nextInt(5));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

------------------------------------
1 start work...
3 start work...
3 phase 1 end.
2 start work...
4 start work...
1 phase 1 end.
4 phase 1 end.
3 phase 2 end.
2 phase 1 end.
all task phase 1 end.
2 phase 2 end.
1 phase 2 end.
4 phase 2 end.

2.6 awaitAdvance

(1) 不会报告已到达

public class MyPhaser4 {
    public static void main(String[] args) {
        final Phaser phaser = new Phaser(3);
        new Thread(()->phaser.awaitAdvance(phaser.getPhase())).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("arrived parties: " +phaser.getArrivedParties());
    }
}
----------------
arrived parties: 0

(2) 传入的Phase,与当前实际的Phase一致,则阻塞住;与当前实际的Phase不一致,立即返回

public static void main(String[] args) {
        final Phaser phaser = new Phaser(3);
        // phaser.awaitAdvance(phaser.getPhase()); //阻塞,不会打印end
        //phaser.awaitAdvance(2); //不阻塞,会打印end
        System.out.println("end");
    }

(3) 虽然主线程不参于报到,但依然可以阻塞等待所有任务

public class MyPhaser4 {
    private final static Random random = new Random(System.currentTimeMillis());

    public static void main(String[] args) {
        final Phaser phaser = new Phaser(3);
        IntStream.rangeClosed(0, 3).boxed().map(i -> phaser).forEach(ArriveTask::new);

        phaser.awaitAdvance(phaser.getPhase()); 
        System.out.println("=====");
    }

    private static class ArriveTask extends Thread {
        private final Phaser phaser;

        public ArriveTask(Phaser phaser) {
            this.phaser = phaser;
            start();
        }

        @Override
        public void run() {
            System.out.println(getName() + " start...");
            mysleep();
            phaser.arriveAndAwaitAdvance();
            System.out.println(getName() + " end");
        }
    }

    private static void mysleep(){
        try {
            TimeUnit.SECONDS.sleep(random.nextInt(5));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
------
Thread-0 start...
Thread-2 start...
Thread-3 start...
Thread-1 start...
Thread-2 end
=====
Thread-1 end
Thread-0 end

2.7 awaitAdvanceInterruptibly

可中断的awaitAdvance

public class MyPhaser5 {
    public static void main(String[] args) {
        final Phaser phaser = new Phaser(3);

        Thread thread =  new Thread(()->{
            try {
                phaser.awaitAdvanceInterruptibly(phaser.getPhase());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread.interrupt();

    }
}

2.8 forceTermination

强制结束phaser

public class MyPhaser6 {
    public static void main(String[] args) throws InterruptedException {
        final Phaser phaser = new Phaser(3);

        new Thread(phaser::arriveAndAwaitAdvance).start();

        TimeUnit.SECONDS.sleep(3);
        System.out.println("phaser state: " +  phaser.isTerminated());

        phaser.forceTermination();
        System.out.println("phaser state: " +  phaser.isTerminated());

    }
}

----------------------
phaser state: false
phaser state: true

2.9 综合例子

总共六位同学要参加同学聚会,聚会流程有三项:吃饭、K歌、看电影。六位同学都要吃饭,但是吃完饭后只有四位同学想K歌,K完歌后只有两位同学想看电影。实现这样的场景,用CyclicBarrier和CountDownLatch显然不太方便。这时就可以使用Phaser。

Phaser定义流程:
     首先定义聚会流程,定义子类PartyPhaser来实现Phaser,并且重写onAdvance方法

import java.util.concurrent.Phaser;

/**
 * @author sicimike
 */
public class PartyPhaser extends Phaser {

    @Override
    protected boolean onAdvance(int phase, int registeredParties) {
        switch (phase) {
            case 0:
            	// 所有注册的线程都到达第一个屏障后,执行这个case
                System.out.println("所有人均已吃完,共:" + registeredParties + " 人");
                return false;
            case 1:
            	// 所有注册的线程都到达第二个屏障后,执行这个case
                System.out.println("所有人均已达到KTV,共:" + registeredParties + " 人");
                return false;
            case 2:
            	// 所有注册的线程都到达第三个屏障后,执行这个case
                System.out.println("所有人均已到达电影院,共:" + registeredParties + " 人");
                return true;
            default:
                return true;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值