高考考试网
当前位置: 首页 高考资讯

ase缓存机制(Phaser并发阶段器)

时间:2023-05-31 作者: 小编 阅读量: 2 栏目名: 高考资讯

Phaser并发阶段器Phaser由JDK1.7提出,是一个复杂强大的同步辅助类,是对同步工具类CountDownLatch和CyclicBarrier的综合升级,能够支持分阶段实现等待的业务场景。但是,这个错误可能会导致{@codeIllegalStateException}仅在一些后续操作这个相位器,如果有的话。Phaser解决分科考试问题从体验的示例中其实没看出其优势在哪里,上诉场景完全可以采用CountDownLatch,所以现在换一种场景来说明Phaser的优势。

Phaser并发阶段器

Phaser由JDK1.7提出,是一个复杂强大的同步辅助类,是对同步工具类CountDownLatch和CyclicBarrier的综合升级,能够支持分阶段实现等待的业务场景。

我们可以回忆下CountDownLatch讲的是先指定N个线程,在N个线程干完活之前,其它线程都需要等待(导游等待旅游团所有人上车才能开车),而CyclicBarrier讲的是先指定N个线程。等N个线程到齐了大家同时干活(多个驴友相约去旅游,先到的需要等待后来的),而Phaser是两者的结合,可以理解为先指定N个线程,等N个线程到齐后开始干第一阶段的活,等第一阶段所有的线程都干完活了,接着N个线程开始干第二阶段的活,直到所有的阶段完成工作,程序结束,当然需要注意的是每个阶段可以根据业务需要新增或者删除一些线程,并不是开始指定多少个线程每个阶段就必须有多少个线程。

入门体验

看了概念可能不容易理解,从一个小demo入手体验下

publicclassPhaserDemo1{//指定随机种子privatestaticRandomrandom=newRandom(System.currentTimeMillis());publicstaticvoidmain(String[]args){Phaserphaser=newPhaser();//将线程注册到phaserphaser.register();for(inti=0;i<5;i){Tasktask=newTask(phaser);task.start();}phaser.arriveAndAwaitAdvance();System.out.println("alltaskexecuteclose");}staticclassTaskextendsThread{Phaserphaser;publicTask(Phaserphaser){this.phaser=phaser;this.phaser.register();}@Overridepublicvoidrun(){try{System.out.println(Thread.currentThread().getName() "开始执行");TimeUnit.SECONDS.sleep(random.nextInt(5));System.out.println(Thread.currentThread().getName() "执行完毕");//类似CountDownLatch中的awaitphaser.arriveAndAwaitAdvance();}catch(InterruptedExceptione){e.printStackTrace();}}}}

不知道有没有这样的疑惑,phaser.register是向phaser去注册这个线程,那么为什么主线程也需要注册呢?

其实很简单主线程需要等待所有子线程执行完毕才能继续往下面执行所以必须要phaser.arriveAndAwaitAdvance();阻塞等待,而这个语句是意思当前线程已经到达屏障,在此等待一段时间等条件满足后需要向下一个屏障继续执行,如果没有主线程的phaser.register,直接调用phaser.arriveAndAwaitAdvance,在源码中提到可能会有异常,所以必须在主程序中注册phaser.register();

/*<p>Itisausageerrorforanunregisteredpartytoinvokethis*method.However,thiserrormayresultinan{@code*IllegalStateException}onlyuponsomesubsequentoperationon*thisphaser,ifever.*/译:未注册方调用此函数是一个使用错误方法。但是,这个错误可能会导致{@codeIllegalStateException}仅在一些后续操作这个相位器,如果有的话。

Phaser解决分科考试问题

从体验的示例中其实没看出其优势在哪里,上诉场景完全可以采用CountDownLatch,所以现在换一种场景来说明Phaser的优势。

假设某校举行期末考试,有三门考试语文、数学、英语,每门课允许学生提前交卷,只有当所有学生完成考试后才能举行下一次的考试,这就是典型的分阶段任务处理,示例图如下。

将上诉场景语义化如下

publicclassPhaserExam{publicstaticRandomrandom=newRandom(System.currentTimeMillis());publicstaticvoidmain(String[]args){//一次初始化2个相当于两次registerPhaserphaser=newPhaser(2);for(inti=0;i<2;i){Examexam=newExam(phaser,random.nextLong());exam.start();}}staticclassExamextendsThread{Phaserphaser;Longid;publicExam(Phaserphaser,Longid){this.phaser=phaser;this.id=id;}@Overridepublicvoidrun(){try{System.out.println(Thread.currentThread().getName() "===开始语文考试");TimeUnit.SECONDS.sleep(random.nextInt(5));System.out.println(Thread.currentThread().getName() "===结束语文考试");phaser.arriveAndAwaitAdvance();System.out.println(Thread.currentThread().getName() "===开始数学考试");TimeUnit.SECONDS.sleep(random.nextInt(5));System.out.println(Thread.currentThread().getName() "===结束数学考试");phaser.arriveAndAwaitAdvance();System.out.println(Thread.currentThread().getName() "===开始英语考试");TimeUnit.SECONDS.sleep(random.nextInt(5));System.out.println(Thread.currentThread().getName() "===结束英语考试");phaser.arriveAndAwaitAdvance();}catch(InterruptedExceptione){e.printStackTrace();}}}}

代码执行结果如下,可以看到三个阶段都是等待所有线程执行完毕后才往下执行,相当于多个栅栏。

到这里请注意,通过Phaser类的构造方法构建的party数,也就是线程数需要和循环的次数对应,不然可能影响后续阶段器的正常运行。

两个重要状态

在Phaser内有2个重要状态,分别是phase和party,乍一看很难理解,他们的定义如下。

phase就是阶段,如上面提到的语文、数学、英语考试这每个考试对应一个阶段,不过phase是从0开始的,当所有任务执行完毕,准备进入下一个阶段时phase就会加一。

party对应注册到Phaser线程数,party初始值有两种形式

  • 方法一就是通过Phaser的有参构造初始化party值。
  • 方法二采用动态注册方法phaser.register()或phaser.bulkRegister(线程数)指定线程数,注销线程调用phaser.arriveAndDeregister()方法party值会减一。
Phaser常用API

Phaser常用API总结如下所示

//获取Phaser阶段数,默认0publicfinalintgetPhase();//向Phaser注册一个线程publicintregister();//向Phaser注册多个线程publicintbulkRegister(intparties);//获取已经注册的线程数,也就是重要状态party的值publicintgetRegisteredParties();//到达并且等待其它线程到达publicintarriveAndAwaitAdvance();//到达后注销不等待其它线程,继续往下执行publicintarriveAndDeregister();//已到达线程数publicintgetArrivedParties();//未到达线程数publicintgetUnarrivedParties();//Phaser是否结束只有当party的数量是0或者调用方法forceTermination时才会结束publicbooleanisTerminated();//结束PhaserpublicvoidforceTermination();

代码演示如下

publicclassPhaserApiTest{publicstaticvoidmain(String[]args)throwsInterruptedException{Phaserphaser=newPhaser(5);System.out.println("当前阶段" phaser.getPhase());System.out.println("注册线程数===" phaser.getRegisteredParties());//向phaser注册一个线程phaser.register();System.out.println("注册线程数===" phaser.getRegisteredParties());//向phaser注册多个线程,批量注册phaser.bulkRegister(4);System.out.println("注册线程数===" phaser.getRegisteredParties());newThread(()->{//到达且等待phaser.arriveAndAwaitAdvance();System.out.println(Thread.currentThread().getName() "===执行1");}).start();newThread(()->{//到达不等待,从phaser中注销一个线程phaser.arriveAndDeregister();System.out.println(Thread.currentThread().getName() "===执行2");}).start();TimeUnit.SECONDS.sleep(3);System.out.println("已到达线程数===" phaser.getArrivedParties());System.out.println("未到达线程数===" phaser.getUnarrivedParties());System.out.println("Phaser是否结束" phaser.isTerminated());phaser.forceTermination();System.out.println("Phaser是否结束" phaser.isTerminated());}}

执行结果如下所示

arriveAndAwaitAdvance解析

arriveAndAwaitAdvance是Phaser中一个重要实现阻塞的API,其实arriveAndAwaitAdvance是由arrive方法和awaitAdvance方法合并而来,两个方法的作用分别为

  • arrive:到达屏障但不阻塞,返回值为到达的阶段号。
  • awaitAdvance(int):接收一个 int 值的阶段号,在指定的屏障处阻塞。

测试代码如下

publicclassPhaserTestArrive{publicstaticRandomrandom=newRandom(System.currentTimeMillis());publicstaticvoidmain(String[]args){Phaserphaser=newPhaser(5);for(inti=0;i<5;i){newTask(i,phaser).start();}phaser.register();//主线程需要调用arrive的原因是主线程注册的第六个线程还未到达,需要手动到达,才能调用awaitAdvance阻塞屏障phaser.arrive();//因为Phaser线程数为6,所以即使5个线程已经到达,但是还差主线程的一个,目前阶段数就是0phaser.awaitAdvance(0);System.out.println("alltaskisend");}staticclassTaskextendsThread{Phaserphaser;publicTask(intnum,Phaserphaser){super("Thread--" String.valueOf(num));this.phaser=phaser;}@Overridepublicvoidrun(){try{System.out.println(Thread.currentThread().getName() "===task1isstart");TimeUnit.SECONDS.sleep(random.nextInt(3));System.out.println(Thread.currentThread().getName() "===task1isend");//到达且不等待phaser.arrive();System.out.println(Thread.currentThread().getName() "===task2isstart");TimeUnit.SECONDS.sleep(random.nextInt(3));System.out.println(Thread.currentThread().getName() "===task2isend");}catch(InterruptedExceptione){e.printStackTrace();}}}}

中断响应

我们需要特别注意的就是Phaser所有API中只有awaitAdvanceInterruptibly是响应中断的,其余全部不会响应中断所以不需要对其进行异常处理,演示如下

publicstaticvoidmain(String[]args){Phaserphaser=newPhaser(3);ThreadT1=newThread(()->{try{phaser.awaitAdvanceInterruptibly(phaser.getPhase());}catch(InterruptedExceptione){System.out.println("中断异常");e.printStackTrace();}//phaser.arriveAndAwaitAdvance();});T1.start();T1.interrupt();phaser.arriveAndAwaitAdvance();}

    推荐阅读
  • 危险品车跨地区营运罚款多少(小火车纷纷开进商场)

    据某商场市场部工作人员介绍,商场的儿童业态有强大的“虹吸效应”,一个儿童可能带来2个甚至4个家长,“这也是商场小火车火爆的原因。”一般来说,一辆小火车由一个火车头和四节车厢组成,如果满员的话,可以坐下20个乘客,再加上一名驾驶员。据她了解,大型游乐设施需要相应资质,但小火车暂无相关规定。

  • 孕酮值偏低对胎儿有影响吗(孕酮太低对胎儿有什么影响)

    4、停胎孕酮在生育过程中帮助刺激子宫变化,并通过增加生殖系统血管和组织血流促进胚胎发育。

  • 枇杷是什么(关于枇杷的简介)

    下面希望有你要的答案,我们一起来看看吧!枇杷是什么枇杷是蔷薇科、枇杷属植物。枇杷是美丽观赏树木和果树,枇杷果肉柔软多汁,风味鲜美,且在初夏成熟,正在鲜果淡季,因此颇受广大消费者欢迎。除鲜食外,还可制成罐头、蜜饯、果膏、果酒及饮料等。枇杷含有丰富的蛋白质、维生素、纤维素、糖分、氨基酸以及钙、铁、磷等成分,适量食用对身体有益。

  • 软组织损伤的治疗处方(巧用栀子治疗闭合性软组织损伤)

    平时户外运动较多的人们,有时不慎就会受伤,比如崴脚后踝关节肿胀,皮肤没有破溃,无裂口与外界相通,损伤时的出血积聚在组织内,这称为闭合性软组织损伤。是受钝力作用,肌肉猛烈收缩,关节活动超越正常范围或劳损等引起。药物便宜,操作简便,疗效优良,今天就来介绍一下“巧用栀子治疗闭合性软组织损伤”。同时适当抬高患肢,局部尽量制动休息。每24小时更换药物1次。如果三天无效请立即就医以免耽误病情。

  • 与12生肖有关的成语50则(七十多个与生肖有关的趣味成语汇总)

    比喻极大数量中极微小的数量,微不足道。表示对同盟的死亡或不幸的伤心。比喻势均力敌的各方之间,斗争或竞赛十分激烈。比喻因疑神疑鬼而引起恐惧。比喻做法不谨慎,反使对方有所戒备。形容迅速取得成就。比喻出了问题以后想办法补救,可以防止继续受损失。比喻以好的名义做幌子,实际上名不副实或做坏事。比喻用惩罚某个个体的办法来警告别的人。比喻贪图眼前的好处而不顾长远利益。比喻走投无路时不顾一切地采取极端的行动。

  • 吃鸡新体验服ak怎么升级(玩家测试新版本获光子奖励7套新衣服)

    现如今3月23日玩家进入到体验服之后,又一次得到了7件新衣服的奖励,其中6个紫色级别和1个粉色级别。通过几天的体验服测试之后,天哥个人觉得沙漠2.0有3个不错的改变或者说是特色!至于正式服何时开启新版本,天哥个人预测应该已经为时不远了,本周差不多能与大家见面。不过也可能会延迟到下周,毕竟到目前为止,正式服的游戏中仍然没有开启“倒计时”,所以或许会因此延迟一些。

  • 红字增值税专用发票如何报税(红字增值税发票开票流程)

    红字增值税专用发票如何报税增值税一般纳税人开具增值税专用发票后,发生销货退回、开票有误,应税服务中止等情形但不符合发票作废条件,或者因销货部分退回及发生销售折让,需要开具红字专用发票。

  • 兰花什么时候换盆好(春季冬季换盆好)

    以下内容希望对你有帮助!第一个是春天3-4月份的时候,第二个是秋天9-10月份的时候。这两段时间天气温暖,植株生长速度较快,所以比较适合换盆。不建议在夏季或者冬季换盆,但如果花盆太小或者不够透气,严重影响到植株生长,那么需要及时于于温暖的室内更换,以保证植株能健康生长。

  • 使命召唤手游大炮怎么用(使命召唤大炮的使用方法)

    对于比较猥琐的敌人,也可以千里索命。使命召唤手游中房屋是无法被摧毁的。爆破模式中,空对地导弹尽量攻击那些拆包、安包、卡点的敌人。据点模式中,空对地导弹对付据点内的敌方火力点是很好的选择。空对地导弹的引导显示屏不仅仅是用来瞄准引导导弹攻击敌人,更可以给队伍带来情报。空对地导弹发射后,引导状态下点击屏幕是可以使导弹加速的~

  • 小学生励志唯美句子摘抄大全(小学生励志唯美句子摘抄锦集)

    与其逃避现实,不如笑对人生。在逆境中,智者知难而进,愚者消沉不前。与其抱怨这个世界不美好,不如用自己的努力,争取更多的美好和幸运。立即行动,永远不晚!记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。所以,牛逼时不要得瑟,落魄时不要堕落。人生的累对于大多数人来说,都是不可避免的。把握时代新特征、探索工作新规律、开创事业新局面。也许,每一个人个体,就是一处风景,不同的风景。