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

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

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

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();}

    推荐阅读
  • 零跑t03的前车盖怎么打开(车窗按键说明图解)

    关于小零的车窗按键,你都会使用吗?将转轮上的白色刻线转到“L”,可以调节左后视镜;转到“R”则可以调节右后视镜[害羞R]。然后是前排车窗的升降,后边是车窗锁止;再往后是后排车窗升降,最后面的是车门解锁和上锁。这些功能按键,全部都集中在主驾驶座的左手边哦~抬手就可以按到啦!#汽车#新能源汽车#零跑#零跑T03#车窗#按键功能#汽车知识举报/反馈发表评论

  • 世界悠悠球大赛无冕之王(21岁小伙玩悠悠球10年)

    按这个说法,21岁的文海溢可能就是当下活跃在重庆悠悠球界的“头号玩家”。今天的邀请赛上,20多位重庆本土高手以及几位受邀参加的全国冠军级别大神在台上秀出了不同风格的表演。然而第一个登台的选手,就放起了“青城山下白素贞”,来自重庆理工大学的王建,选择了好妹妹乐队这首抒情缓慢的歌曲,不紧不慢之间,将手中的线编织成一幅幅精美的图案,被在场玩家戏称为“养生玩法”。

  • 秋天发财树叶子发黄怎么回事(秋天发财树叶子发黄怎么回事儿)

    很多人在养殖发财树的时候都会发现,就在秋季的时候它的叶子总是会出现发黄的情况,这是怎么回事呢?秋天发财树叶子发黄原因有很多,首先没有施肥,秋季需要很多的养分,长时间没有施肥就会导致黄叶,需要及时给它做好追肥的工作,提供更多的养分。其次生病生虫,当它出现了病虫害之后也会发生黄叶,要把病叶和害虫及时清理掉,喷杀虫剂治疗。还有可能是土壤不适合,阳光直射,空气干燥造成的。

  • 长沙市一日游必去景点(去长沙市哪里比较好玩)

    长沙市一日游必去景点岳麓山。位于长沙市的湘江西岸,山中名胜古迹众多。喜欢登山的游客这是必选之处。湖南大学也位于山下,可以去参观、参观湖南大学的风格,而且该景区免费开放,乘坐“旅3路区间”车即可到达。可在长沙汽车西站乘坐918路公交车,大约2小时可到达。

  • 酸奶优格的做法(怎样做酸奶优格)

    跟着小编一起来看一看吧!酸奶优格的做法用料:酸奶1盒、香蕉,洛神花适量、蓝莓干,蔓越莓干适量。准备酸奶一盒,打开备用。准备食材香蕉1/3根,去皮切片备用。将洛神花,蓝莓干,蔓越莓干放入碗中,放入香蕉。用电动搅拌器打碎,然后倒入酸奶。搅拌搅匀,家里有山楂糕,切几块放进去,再加几块伽师瓜,酸奶优格就做好了,营养丰富,酸甜可口。

  • 宝宝多大可以睡枕头 宝宝多大可以睡枕头睡觉?

    如果此时不用枕头,头位偏低,会使脑部血液比用枕头时多,可能影响婴儿入睡。因此,3个月宝宝应开始使用枕头。如果枕头过软,容易导致宝宝窒息,而过硬又不适合小儿颅骨柔软的特点,容易导致孩子颅骨变性。枕套以纯棉布为最优。宝宝用多高的枕头枕头过高、过低都不利于宝宝睡眠和身体正常发育。枕心软硬度要合适,以松软不变形的物品为好。

  • 木瓜和什么煲汤最好(木瓜和什么煲汤最好养胃)

    木瓜的营养丰富,它的功效除了我们常听到的丰胸之外,还可以调理脾胃,促进消化,美容养颜。做法:1.木瓜去皮,去籽,洗净,切成大块;红枣洗净,去核。木瓜花生鱼尾汤润肠通便材料:木瓜300克,鲩鱼尾300克,花生100克,生姜4片。

  • 两性之间女人在乎什么(两性交往中女人最渴望被伴侣满足的三种)

    尤其是恋爱中的女性,更希望自己是恋人的例外和偏爱。女人的爱情是细腻的,男人的爱情是漫不经心的。在生活中,当女人感到沮丧或不适时,很容易感到孤独。陪伴是最好的礼物,陪伴也是最好的行动证明。但是,想要达到这个目标,不能光靠努力,必须要有正确的方法。真正的感情需要相互关心和珍惜。知道男女的需求,真心付出,一定会赢得女性的真爱,共同创造美好幸福的生活。

  • 小米手机自动开关机怎么设置(小米手机自动开关机的设置步骤)

    接下来我们就一起去了解一下吧!小米手机自动开关机怎么设置在手机页面找到“安全中心”APP,图标是绿色的一个盾上面有一个白色的闪电。您可以在这里设置关闭一些异常耗电的APP,在“其它设置”栏找到“定时开关机”然后点击左侧的箭头。在“定时开机”栏左侧点击这个开关,然后设置想要开机的时间,在“定时关机”左侧点击开关,然后设置定时关机的时间,设置完成后,点击左上角的对号,然后定时开关机就设置好了。

  • 三杯鸡做法(怎么做三杯鸡)

    三杯鸡做法食材:三黄鸡、香菇、红椒、色拉油、姜、蒜、料酒、生抽、老抽、香油、植物油、白糖、白胡椒。鸡肉洗净,切小块放入容器中,加1汤勺料酒、白胡椒粉、姜片、蒜拌匀,腌制20分钟。炒锅倒入植物油,烧至5成热,倒入腌好的鸡肉和腌鸡肉的姜片和蒜,炸至断生捞出。将炸好的鸡肉块放入砂锅中,倒入生抽、糖、老抽、香菇块,大火烧开,再转小火焖10分钟,之后开大火收汁,最后加入白糖、香油调味即可。