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

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

    推荐阅读
  • 拍半身照专业技巧(半身特写拍照技巧)

    事实上,它有很多种变化:双臂松紧程度、手掌的状态、身体的朝向……调整这些因素,抱臂的效果就完全不同。拍男性一般会拍正面,显肩宽;胳膊要抱紧些,尽量少露或不露出手掌。由于存在支撑平面,无论什么样的手部动作都不会有不自然的倾斜感。

  • 白毫银针是哪类茶(白毫银针是白茶类)

    以下内容希望对你有帮助!白毫银针是哪类茶白毫银针,属于白茶类,为白茶中的佼佼者,也是价值最高的白茶。白毫银针,素有茶中“美女”、“茶王”之美称。白毫银针由福建省的汉族茶农创制,产地位于中国福建省的福鼎市和南平市政和县。白毫银针,创制于1796年,中国六大茶类之一的白茶,原产地在福建,主要产区为福鼎、政和、松溪、建阳等地,属有中国十大名茶的称号,素有茶中“美女”、“茶王”之美称。

  • 序和跋是什么意思(序和跋什么意思)

    序和跋是什么意思序在古代另有一种序是惜别赠言的文字,叫作“赠序”,内容多是对于所赠亲友的赞许、推重或勉励之辞,是临别赠言性质的文体。跋是文体的一种,写在书籍,文章或书画作品的后面。序和跋是叙述一书作意的文字,也是一种文体。而置于书后的则称作“跋”,也叫后序,后记,题跋,跋尾等。写在跋中的文字则要灵活一些,多是有感而发,或抒情,考订,议论,可长可短,不拘一格。

  • 仙人掌适合什么土壤(仙人球要用什么土壤种)

    跟着小编一起来看一看吧!仙人掌适合什么土壤仙人掌使用的土壤要求沙土,需要排水性好,还要松软透气。日常可使用壤土、腐叶土、粗砂、石灰按2:2:3:1混合,或用腐殖土、沙土、砻糠灰按6:4:2混合。5-9月份可适当浇水,晚秋开始减少。它喜欢阳光,应给予充足光照。最适宜温度为20-30℃,冬季保持5℃以上。

  • 怎样做甜酒酿好吃窍门(甜酒怎么做)

    我们一起去了解并探讨一下这个问题吧!怎样做甜酒酿好吃窍门材料:糯米、甜酒曲、温开水。将糯米清洗干净,浸泡12小时。蒸笼中铺上一块纱布,放入泡好的糯米,铺平,用手指戳几个洞,盖上盖子,蒸30分钟左右。将蒸好的糯米放入干净的容器中,捣散,使糯米降温。在甜酒曲中加入温开水,搅拌均匀后倒入糯米中,将糯米搅拌均匀。将拌好的糯米放入干净的容器中,填平后在中间戳一个洞,盖紧,将糯米放在温暖的地方发酵至出甜酒即可。

  • 今年国庆节火车票什么时候开售(国庆假期火车票17日开售)

    据介绍,除了推行“落地检”之外,旅客需持有48小时内核酸检测阴性证明乘坐飞机、高铁、列车、跨省长途客运汽车、跨省客运船舶等交通工具。入住宾馆、酒店和进入旅游景区等人流密集场所时,查验健康码和72小时内核酸检测阴性证明。吴良有称,假期临近,人员流动性增加,倡导广大群众国庆假期在本地过节,尽量减少跨地市出行,避免人群大范围流动引发的疫情传播风险。

  • 如何在桌面上养宠物(如何在桌面上养宠物鱼)

    4、宠物猫启动后,在任务栏是看不到图标的,鼠标移动到猫猫身上,点击“右键”,可看到“功能菜单”,点击“Exit”便可关闭宠物猫。

  • 360随身wifi变为无线网卡(360随身WiFi作为无线网卡)

    台式机实现WiFi无线上网。由于台式主机离开宽带接口较远,所以决定使用360随身WiFi打开包装,包装盒上有简单的安装说明由于不想安装全家桶(你懂的),所以去官网下载驱动然后安装驱动驱动程序安装完成,会提示插入随身WiFi由于台式机本身没有连接有线宽带,所以几秒钟后驱动程序会检测到我们需要的是无线网卡模式等待几秒钟后,安装就完成了。可以在无线信号列表查看并连接WiFi信号。

  • 92的车加了95会怎么样(92的车加了95会有事吗)

    如果你本来使用92号油的车上加了95号油,那是无伤大雅的,就好比本来是吃馒头,你给他个鸡腿一样,我来为大家科普一下关于92的车加了95会怎么样?下面希望有你要的答案,我们一起来看看吧!也就是本来加95号油的车里加了92号油,那对于车造成的损伤也是比较难受的,这个所以千万注意。

  • 正真的良心国产抗日剧(国产抗日剧的8个神套路)

    脑残剧情一、鬼子全部低智商:国产抗战影视剧,都会发现凡是鬼子都是智商低得可怜,平均智商估计不超过二十。估计是以前八路军新四军国军的抗战传奇都拍厌了,干脆来弄点草根抗日传奇岂不是更好。比如抗战初期出现的斯登、M3、五四式。