Java并发编程 - Phaser类的使用
在JAVA 1.7引入了一个新的并发API:Phaser(移相器) , 一个可重用的同步barrier 。 在此前 , JAVA已经有CyclicBarrier、CountDownLatch这两种同步barrier , 但是Phaser更加灵活 , 而且侧重于“重用” 。
一、简述1、注册机制:与其他barrier不同的是 , Phaser中的“注册的同步者(parties)”会随时间而变化 , Phaser可以通过构造器初始化parties个数 , 也可以在Phaser运行期间随时加入(register)新的parties , 以及在运行期间注销(deregister)parties 。 运行时可以随时加入、注销parties , 只会影响Phaser内部的计数器 , 它建立任何内部的bookkeeping(账本) , 因此task不能查询自己是否已经注册了 , 当然你可以通过实现子类来达成这一设计要求 。
Java代码
//伪代码Phaser phaser = new Phaser();phaser.register();//parties count: 1....phaser.arriveAndDeregister()://count : 0;....
此外 , CyclicBarrier、CountDownLatch需要在初始化的构造函数中指定同步者的个数 , 且运行时无法再次调整 。
Java代码
CountDownLatch countDownLatch = new CountDownLatch(12);//count deregister parties after all//parties count is 12 all the times//if you want change the number of parties, you should create a new instance.CyclicBarrier cyclicBarrier = new CyclicBarrier(12);
2、同步机制:类似于CyclicBarrier , Phaser也可以awaited多次 , 它的arrivedAndAwaitAdvance()方法的效果类似于CyclicBarrier的await() 。 Phaser的每个周期(generation)都有一个phase数字 , phase 从0开始 , 当所有的已注册的parties都到达后(arrive)将会导致此phase数字自增(advance) , 当达到Integer.MAX_VALUE后继续从0开始 。 这个phase数字用于表示当前parties所处于的“阶段周期” , 它既可以标记和控制parties的wait行为、唤醒等待的时机 。
1)Arrival:Phaser中的arrive()、arriveAndDeregister()方法 , 这两个方法不会阻塞(block) , 但是会返回相应的phase数字 , 当此phase中最后一个party也arrive以后 , phase数字将会增加 , 即phase进入下一个周期 , 同时触发(onAdvance)那些阻塞在上一phase的线程 。 这一点类似于CyclicBarrier的barrier到达机制;更灵活的是 , 我们可以通过重写onAdvance方法来实现更多的触发行为 。
2)Waiting:Phaser中的awaitAdvance()方法 , 需要指定一个phase数字 , 表示此Thread阻塞直到phase推进到此周期 , arriveAndAwaitAdvance()方法阻塞到下一周期开始(或者当前phase结束) 。 不像CyclicBarrier , 即使等待Thread已经interrupted , awaitAdvance方法会继续等待 。 Phaser提供了Interruptible和Timeout的阻塞机制 , 不过当线程Interrupted或者timeout之后将会抛出异常 , 而不会修改Phaser的内部状态 。 如果必要的话 , 你可以在遇到此类异常时 , 进行相应的恢复操作 , 通常是在调用forceTermination()方法之后 。
Phaser通常在ForkJoinPool中执行tasks , 它可以在有task阻塞等待advance时 , 确保其他tasks的充分并行能力 。
3、中断(终止):Phaser可以进入Termination状态 , 可以通过isTermination()方法判断;当Phaser被终止后 , 所有的同步方法将会立即返回(解除阻塞) , 不需要等到advance(即advance也会解除阻塞) , 且这些阻塞方法将会返回一个负值的phase值(awaitAdvance方法、arriveAndAwaitAdvance方法) 。 当然 , 向一个termination状态的Phaser注册party将不会有效;此时onAdvance()方法也将会返回true(默认实现) , 即所有的parties都会被deregister , 即register个数为0 。
4、Tiering(分层):Phaser可以“分层” , 以tree的方式构建Phaser来降低“竞争” 。 如果一个Phaser中有大量parties , 这会导致严重的同步竞争 , 所以我们可以将它们分组并共享一个parent Phaser , 这样可以提高吞吐能力;Phaser中注册和注销parties都会有Child 和parent Phaser自动管理 。 当Child Phaser中中注册的parties变为非0时(在构造函数Phaser(Phaser parent,int parties) , 或者register()方法) , Child Phaser将会注册到其Parent上;当Child Phaser中的parties变为0时(比如由arrivedAndDegister()方法) , 那么此时Child Phaser也将从其parent中注销出去 。
5、监控:同步的方法只会被register操作调用 , 对于当前state的监控方法可以在任何时候调用 , 比如getRegisteredParties()获取已经注册的parties个数 , getPhase()获取当前phase周期数等;因为这些方法并非同步 , 所以只能反映当时的瞬间状态 。
二、常用的Barrier比较1、CountDownLatch
Java代码
//创建时 , 就需要指定参与的parties个数int parties = 12;CountDownLatch latch = new CountDownLatch(parties);//线程池中同步taskExecutorService executor = Executors.newFixedThreadPool(parties);for(int i = 0; i
- 现状|程序员现状揭秘:平均年薪20.36万,Java人才需求量最大
- Store|苹果将在韩国开设第二家Apple Store直营店 并发布纪念壁
- Linux(服务器编程):百万并发服务器系统参数调优
- 程序员学英语第1天——JavaScript 程序测试的介绍1
- 三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经
- 《深入理解Java虚拟机》:对象创建、布局和访问全过程
- 菜鸟学编程,不懂C++ this指针?还不赶快来学一学
- java面试题整理
- Kotlin集合vs Kotlin序列与Java流
- 编程猫领衔,9家编程app测评一览详解