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

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

    推荐阅读
  • 洋葱生吃还是熟吃有降血糖的效果(蔬菜皇后洋葱生吃还是熟吃)

    不知道是吃洋葱起了作用,还是徐大爷心情变好了,他的血压下降了一点,为此,徐大爷更深信不疑,增加了吃洋葱的量。而药物可以每天服用,对肠胃刺激小,比较安全,对血管也有保护作用,适合长期服用。洋葱个头适中,可凉拌,也可炒菜,还有多种营养,因此也有蔬菜皇后的美誉,它有减少便秘、调节睡眠、增强抵抗力的作用,脾胃虚弱的人也可以食用。

  • 橄榄果和槟榔果分辨(橄榄果和槟榔果如何分辨)

    以下内容希望对你有帮助!橄榄果和槟榔果分辨槟榔果:槟榔果多呈长圆形或卵球形,果实长3-5厘米,颜色青绿或橙黄,中果皮厚,纤维质。橄榄果:橄榄果的形状多呈卵圆形或纺锤形,长2.5-3.5厘米,外表光滑均匀,颜色呈青绿色,成熟后颜色变深,呈黄绿色,无毛,外果皮厚,干时有皱纹。

  • 武汉郁金香主题公园春季游玩攻略 武汉郁金香主题公园好玩吗

    武汉郁金香主题公园向日葵花、郁金香、粉黛乱子草开花的时候是最美的,今年的中秋节5万株向日葵花将陆续开放,同时粉黛乱子草也迎合了中秋国庆的需要。

  • 穿越火线早已被人遗忘的模式(穿越火线巅峰时期的三大热门模式)

    反正是大街小巷各大小网吧中,只要是玩射击游戏首选“穿越火线”,同时CF包含的玩家大多辐射到00后一80后这个年龄层。说到穿越火线当前比较热门的对战模式,应该分为:爆破模式、团队竞技运输船、突围模式、生化模式。穿越火线爆破模式最为经典两张地图应该就是黑色城镇和沙漠一灰,黑色城镇作为穿越火线首张爆破地图,虽然参考了CS中的元素,但是加入了创新化改进。对于曾经是穿越火线的爱好者们,你们最中意的是哪个模式呢?

  • 作者安妮全部小说(红发安妮系列小说及其作者)

    21个月后,即1876年9月,母亲去世。1898年3月,外祖父去世。他们恋爱8年,订婚已有5年。1942年4月24日,莫德去世。由于误会,给他们送来一个女孩。莫德与美国5家出版社接洽,均未获采用。失望之余,莫德便将原稿束之高阁。发售不久,即广受好评,赢得热烈的回响。出版6个月后再版6次,其后5年更是缔造再版32次的辉煌记录。

  • 相由心生这句话有道理吗(什么是真正的相由心生)

    什么是真正的相由心生很多人以为“相由心生”是指,人的相貌变化会受自己心态与心理的影响这固然有些道理,但这是误解“相由心生”的真正含义是:外在的事物是由有我们的心境决定的举个例子,大晴天,一个热爱户外运动小伙子会说,这天气。

  • 东北大葱炒什么菜好吃(酱香大葱炒芹菜)

    小贴士这道菜放大葱炒的时候要小火,加入东古薄盐生抽以后出酱香味,一定要少盐,然后开大火炒芹菜一分钟!芹菜的营养功效1.平肝降压菜含酸性的降压成分,临床对于原发性、妊娠性及更年期高血压均有效。它还可以加快粪便在肠内的运转时间,减少致癌物与结肠粘膜的接触达到预防结肠癌的目的。

  • 韭菜鸡蛋火烧怎么和面(三鲜韭菜鸡蛋火烧)

    ,我来为大家科普一下关于韭菜鸡蛋火烧怎么和面?韭菜鸡蛋火烧怎么和面先把水和面放入厨师机,启动2档,8分钟活好以后是一个光滑柔软的面团,放在旁边盖上纱布,醒半小时,我们可以开始准备三鲜韭菜馅儿了木耳海米泡好洗净,切成碎丁三个鸡蛋炒好韭菜洗好沥干水分,切成小丁,和之前的鸡蛋木耳海米放在盆里,加入花生油、花椒粉,盐搅拌均匀面团均等的分好(我分的不是很均等,所以有大有小……

  • 最新版led显示屏行业十强(武汉这家公司获国内首张液晶屏低蓝光认证)

    武汉这家公司获国内首张液晶屏低蓝光认证长江日报-长江网10月9日讯(记者胡义华实习生王心)手机、LED等液晶显示屏上,什么样标准的蓝光,既能保证图像不失真,又能减少对眼睛的伤害?10月9日,长江日报记者从武汉东湖新技术开发区获悉,武汉华星。

  • 醉酒驾车致人伤拘留多久通知家属(醉酒驾车致人伤拘留多久通知家属呢)

    醉酒驾车致人伤,刑事拘留的二十四小时以内会通知家属。《公安机关办理刑事案件程序规定》第一百二十七条除无法通知或者涉嫌危害国家安全犯罪、恐怖活动犯罪通知可能有碍侦查的情形以外,应当在拘留后二十四小时以内制作拘留通知书,通知被拘留人的家属。拘留通知书应当写明拘留原因和羁押处所。