java多线程之Phaser之学生考试

  • 题目

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

  • 题目分析

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

  • 实例

public class PhaserTest {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException
	{
		MyPhaser phaser = new MyPhaser();
		ExecutorService executorService = Executors.newCachedThreadPool();
		CompletionService<String> completionService = new ExecutorCompletionService<String>(
                executorService);
		 int num=5;
		 System.out.println("同学们准备考试了!");
		 for(int i=0;i<num;i++)
		 {
			  completionService.submit(getTask(phaser,4));
		 }
		 String temp= null;
		 for(int j=0;j<num;j++){
	            temp = completionService.take().get();
	            System.out.println(temp + "\t");
	        }
		 phaser.forceTermination();
		 executorService.shutdown();
	}
	
	public static Callable<String> getTask(Phaser phaser,final int phases){
		phaser.register();
		return new Callable<String>() {
			int time = 0;
			int sum=0;
			String action=null;
			@Override
			public String call() throws Exception {
				try {
					 for(int i=0;i<phases;i++)
					 {
						 switch (i) {
						case 0:
							action="到达考场";
							active();
							break;
						case 1:
							action="做第一道题";
							active();
							break;
						case 2:
							action="做第二道题";
							active();
							break;
						case 3:
							action="做第三道题";
							active();
							break;

						default:
							break;
						}
						 
					 }
				} catch (InterruptedException  e) {
					log.error(e.getMessage());
				}
				return Thread.currentThread().getName()+"答题时间"+sum;
			}
			
			void active() throws InterruptedException
			{
				time = new Random().nextInt(10);
				 sum+=time;
				 System.out.println(Thread.currentThread().getName()+action+"需要"+time+"s");
				 Thread.sleep(time*1000);
				 System.out.println(Thread.currentThread().getName()+action+"完成");
				 phaser.arriveAndAwaitAdvance();
			}
			
		};
	}
}
	
	class MyPhaser extends Phaser {
		 
		@Override
		protected boolean onAdvance(int phase, int registeredParties) {
			// TODO Auto-generated method stub
	 
			switch (phase) {
			case 0:
				 System.out.println("所有同学到达考场,开始答第一题");
				break;
			case 1:
				 System.out.println("所有同学第一题答完,开始答第二题");
				break;
			case 2:
				 System.out.println("所有同学第二题答完,开始答第三题");
				break;
			case 3:
				 System.out.println("所有同学第三题答完,考试结束");
				break;

			default:
				break;
			}
	 
			return super.onAdvance(phase, registeredParties);
		}

}
  • Phaser特点

  1. Phaser可以通过register和bulkRegister方法动态增加注册任务的数量,此外也支持通过其构造函数进行指定初始数量。相对的,Phaser也可以通过arriveAndDeregister方法减少注册任务的数量。之前的CyclicBarrier和CountDownLatch,注册的任务数量都必须确定,不能改变。

  2. Phaser可以主动进行终止。被终止之后,Phaser无法调整注册任务的数量。正在等待中的任务会立刻执行。CyclicBarrier和CountDownLatch没有终止的功能。可以通过重写onAdvance方法和使用forceTermination实现Phaser的终止isTerminated方法可以检测phaser是否被终止,如果被终止,就返回true。

  3. Phaser可以分层,如果在同一Phaser注册的线程过多,竞争的开销将会很大。如果对Phaser进行分层,将有效减少竞争的开销,提高吞吐量。但是相应的,单个操作的开销将会变高(如果存在Phaser分层结构,那么父子Phaser之间就需要相互协调,所以单个操作的开销变高)。

    Phaser phaser = new Phaser();
    		
    Phaser childPhaser = new Phaser(phaser);

     

 

 

  • 知识点

  1. 在Phaser内有2个重要状态,分别是phase和party。phase就是阶段,初值为0,当所有的线程执行完本轮任务,同时开始下一轮任务时,意味着当前阶段已结束,进入到下一阶段,phase的值自动加1。
  2. 使用forceTermination方法,phaser将立即终止,所有被阻塞的线程将会继续执行。
  3. Phaser可以通过register和bulkRegister(批量注册)方法动态增加注册任务的数量,此外也支持通过其构造函数进行指定初始数量。相对的,Phaser也可以通过arriveAndDeregister方法减少注册任务的数量。
  4. arrive  告诉phaser对象,当前线程已经执行到这里了,而且将继续执行下去,并且让phaser中的计数器+1。
  5. awaitAdvance  阻塞当前线程,等待当前阶段下其他所有的线程都到达。这个方法需要传入一个参数,如果这个参数和phaser当前周期相同,那么当前线程将进入等待状态。如果这个参数和phaser当前周期不同,那么当前线程立刻结束等待,继续执行。
  6. arriveAndAwaitAdvance 线程执行这个方法之后将会进入等待状态。直到phaser管理的所有线程执行了这个方法,phaser中的计数重置为0,阶段数+1,所有处于等待状态下的线程继续向下执行。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值