在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不能查询自己是否已经注册了,当然你可以通过实现子类来达成这一设计要求。
//伪代码 Phaser phaser = new Phaser(); phaser.register();//parties count: 1 .... phaser.arriveAndDeregister()://count : 0; ....
此外,CyclicBarrier、CountDownLatch需要在初始化的构造函数中指定同步者的个数,且运行时无法再次调整。
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和Timout的阻塞机制,不过当线程Interrupted或者timout之后将会抛出异常,而不会修改Phaser的内部状态。如果必要的话,你可以在遇到此类异常时,进行相应的恢复操作,通常是在调用forceTermination()方法之后。
Phaser通常在ForJoinPool中执行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
//创建时,就需要指定参与的parties个数 int parties = 12; CountDownLatch latch = new CountDownLatch(parties); //线程池中同步task ExecutorService executor = Executors.newFixedThreadPool(parties); for(int i = 0; i < parties; i++) { executor.execute(new Runnable() { @Override public void run() { try { //可以在任务执行开始时执行,表示所有的任务都启动后,主线程的await即可解除 //latch.countDown(); //run //.. Thread.sleep(3000); } catch (Exception e) { } finally { //任务执行完毕后:到达 //表示所有的任务都结束,主线程才能继续 latch.countDown(); } } }); } latch.await();//主线程阻塞,直到所有的parties到达 //latch上所有的parties都达到后,再次执行await将不会有效, //即barrier是不可重用的 executor.shutdown();
2、CyclicBarrier
//创建时,就需要指定参与的parties个数 int parties = 12; CyclicBarrier barrier = new CyclicBarrier(parties); //线程池中同步task ExecutorService executor = Executors.newFixedThreadPool(parties); for(int i = 0; i < parties; i++) { executor.execute(new Runnable() { @Override public void run() { try { int i = 0; while (i < 3 && !barrier.isBroken()) { System.out.println("generation begin:" + i + ",tid:" + Thread.currentThread().getId()); Thread.sleep(3000); //如果所有的parties都到达,则开启新的一次周期(generation) //barrier可以被重用 barrier.await(); i++; } } catch (Exception e) { e.printStackTrace(); } finally { } } }); } Thread.sleep(100000);
3、Phaser
//创建时,就需要指定参与的parties个数 int parties = 12; //可以在创建时不指定parties // 而是在运行时,随时注册和注销新的parties Phaser phaser = new Phaser(); //主线程先注册一个 //对应下文中,主线程可以等待所有的parties到达后再解除阻塞(类似与CountDownLatch) phaser.register(); ExecutorService executor = Executors.newFixedThreadPool(parties); for(int i = 0; i < parties; i++) { phaser.register();//每创建一个task,我们就注册一个party executor.execute(new Runnable() { @Override public void run() { try { int i = 0; while (i < 3 && !phaser.isTerminated()) { System.out.println("Generation:" + phaser.getPhase()); Thread.sleep(3000); //等待同一周期内,其他Task到达 //然后进入新的周期,并继续同步进行 phaser.arriveAndAwaitAdvance(); i++;//我们假定,运行三个周期即可 } } catch (Exception e) { } finally { phaser.arriveAndDeregister(); } } }); } //主线程到达,且注销自己 //此后线程池中的线程即可开始按照周期,同步执行。 phaser.arriveAndDeregister();
三、API简述
1、Phaser():构造函数,创建一个Phaser;默认parties个数为0。此后我们可以通过register()、bulkRegister()方法来注册新的parties。每个Phaser实例内部,都持有几个状态数据:termination状态、已经注册的parties个数(registeredParties)、当前phase下已到达的parties个数(arrivedParties)、当前phase周期数,还有2个同步阻塞队列Queue。Queue中保存了所有的waiter,即因为advance而等待的线程信息;这两个Queue分别为evenQ和oddQ,这两个Queue在实现上没有任何区别,Queue的元素为QNode,每个QNode保存一个waiter的信息,比如Thread引用、阻塞的phase、超时的deadline、是否支持interrupted响应等。两个Queue,其中一个保存当前phase中正在使用的waiter,另一个备用,当phase为奇数时使用evenQ、oddQ备用,偶数时相反,即两个Queue轮换使用。当advance事件触发期间,新register的parties将会被放在备用的Queue中,advance只需要响应另一个Queue中的waiters即可,避免出现混乱。
2、Phaser(int parties):构造函数,初始一定数量的parties;相当于直接regsiter此数量的parties。
3、arrive():到达,阻塞,等到当前phase下其他parties到达。如果没有register(即已register数量为0),调用此方法将会抛出异常,此方法返回当前phase周期数,如果Phaser已经终止,则返回负数。
4、arriveAndDeregister():到达,并注销一个parties数量,非阻塞方法。注销,将会导致Phaser内部的parties个数减一(只影响当前phase),即下一个phase需要等待arrive的parties数量将减一。异常机制和返回值,与arrive方法一致。
5、arriveAndAwaitAdvance():到达,且阻塞直到其他parties都到达,且advance。此方法等同于awaitAdvance(arrive())。如果你希望阻塞机制支持timeout、interrupted响应,可以使用类似的其他方法(参见下文)。如果你希望到达后且注销,而且阻塞等到当前phase下其他的parties到达,可以使用awaitAdvance(arriveAndDeregister())方法组合。此方法的异常机制和返回值同arrive()。
6、awaitAdvance(int phase):阻塞方法,等待phase周期数下其他所有的parties都到达。如果指定的phase与Phaser当前的phase不一致,则立即返回。
7、awaitAdvanceInterruptibly(int phase):阻塞方法,同awaitAdvance,只是支持interrupted响应,即waiter线程如果被外部中断,则此方法立即返回,并抛出InterrutedException。
8、awaitAdvanceInterruptibly(int phase,long timeout,TimeUnit unit):阻塞方法,同awaitAdvance,支持timeout类型的interrupted响应,即当前线程阻塞等待约定的时长,超时后以TimeoutException异常方式返回。
9、forceTermination():强制终止,此后Phaser对象将不可用,即register等将不再有效。此方法将会导致Queue中所有的waiter线程被唤醒。
10、register():新注册一个party,导致Phaser内部registerPaties数量加1;如果此时onAdvance方法正在执行,此方法将会等待它执行完毕后才会返回。此方法返回当前的phase周期数,如果Phaser已经中断,将会返回负数。
11、bulkRegister(int parties):批量注册多个parties数组,规则同10、。
12、getArrivedParties():获取已经到达的parties个数。
13、getPhase():获取当前phase周期数。如果Phaser已经中断,则返回负值。
14、getRegisteredParties():获取已经注册的parties个数。
15、getUnarrivedParties():获取尚未到达的parties个数。
16、onAdvance(int phase,int registeredParties):这个方法比较特殊,表示当进入下一个phase时可以进行的事件处理,如果返回true表示此Phaser应该终止(此后将会把Phaser的状态为termination,即isTermination()将返回true。),否则可以继续进行。phase参数表示当前周期数,registeredParties表示当前已经注册的parties个数。
默认实现为:return registeredParties == 0;在很多情况下,开发者可以通过重写此方法,来实现自定义的advance时间处理机制。
内部原理,比较简单(简述):
1)两个计数器:分别表示parties个数和当前phase。register和deregister会触发parties变更(CAS),全部parties到达(arrive)会触发phase变更。
2)一个主要的阻塞队列:非AQS实现,对于arriveAndWait的线程,会被添加到队列中并被park阻塞,知道当前phase中最后一个party到达后触发唤醒。
相关推荐
Phaser 3.22是该流行JavaScript游戏框架的一个重要版本,它提供了许多新功能、改进和优化,旨在提升开发者的游戏开发体验。Phaser是一个基于HTML5和WebGL的开源游戏框架,广泛用于创建跨平台的网页游戏。在这个最新...
在"phaser-wxdemo-master.zip"这个压缩包中,包含的是一个Phaser-WeChat的示例项目集,它提供了多个演示了Phaser-WX功能和用法的示例游戏。这些示例可以帮助开发者了解如何在实际项目中应用Phaser-WX,从而快速掌握...
刮刮乐游戏通常涉及到用户交互,比如鼠标或触摸操作刮开覆盖层,显示出隐藏的内容,Phaser的事件监听和响应机制可以很好地实现这一功能。 在开发刮刮乐Demo的过程中,开发者可能利用了以下Phaser的关键知识点: 1....
4. **键盘输入处理**:玩家通过键盘控制贪吃蛇的移动,Phaser提供了键盘输入监听功能,可以轻松获取按键事件并响应,调整蛇的移动方向。 5. **动画**:在游戏过程中,可能会有一些简单的动画效果,如吃到食物后的...
富士施乐(xerox) phaser3155驱动软件,英文版
SC则可能指的是Scanner Controller,意味着这个驱动同时包含了扫描功能,使得Phaser 3200MFP不仅能够打印,还能进行扫描操作。 安装驱动的过程一般如下: 1. 首先,确保电脑已连接到打印机,并关闭所有打印任务。 ...
phaser-inspector, Phaser检查器插件允许你检查Phaser游戏 Phaser检查器插件将重新设计 [UPDATE] Phaser检查器插件重新设计和重构,以使它的成为更好的插件。 [UPDATE] Phaser检查器插件支持RenderTexture上的。 ...
它集成了物理引擎、精灵动画、图层管理、音频处理、输入检测等众多功能,使得开发者可以快速构建各种类型的游戏,包括像"切水果"这样的休闲小游戏。 在"小游戏_基于Phaser开发的小游戏之切水果"项目中,我们可以...
10. **界面和音效(UI and Sound Effects)**:Phaser 提供了添加图像、文本和音效的功能,用于创建游戏界面和增强游戏体验。 在压缩包中的 "JavaScript_使用javascript+phaser开发的小游戏之俄罗斯方块" 文件中,...
9. **插件系统**:允许开发者扩展Phaser的功能,添加自定义的组件和功能。 10. **社区支持**:Phaser拥有活跃的社区,提供了大量的教程、示例代码、插件和游戏模板,有助于开发者快速上手。 通过这些核心特性,...
Phaser CE是基于原Phaser框架的社区维护版本,继承了其强大的功能并持续优化更新。 Phaser CE的核心特性包括: 1. **渲染引擎**:支持WebGL和Canvas两种渲染方式,可以根据设备性能自动选择最佳方案。WebGL提供了...
它包含了丰富的功能,如精灵、动画、物理引擎、碰撞检测以及音频处理等,使得开发者可以快速地构建各种类型的游戏。在这个“phaser物理弹球小游戏”项目中,我们可以看到如何利用Phaser2版本来开发一个基于物理规则...
8. **扩展性和插件**:Phaser社区开发了许多插件,涵盖了粒子系统、路径跟踪、图形成形等高级功能,进一步丰富了引擎的功能。 9. **调试工具**:内置的Phaser Debug工具可以帮助开发者快速检查精灵位置、碰撞检测、...
phaser-plugin-isometric, 用于相位图的功能封装的axonometric插件,保持 true 到 Phaser API 请注意,这里插头已经不再在积极发展和与当前版本相位相位兼容无法保证。 fork-更新日志[ 02.12.2015 ] 修复和实用功能...
Phaser是一款广泛使用的开源HTML5游戏框架,专为制作2D游戏而设计。"Phaser游戏入门3接金币1"的标题暗示了我们将探讨如何使用Phaser...通过这个项目,初学者不仅能掌握Phaser的关键功能,还能提升编程和问题解决能力。
Phaser还支持自定义插件,进一步扩展其功能。 总之,“phaser-first-game-resource”压缩包为初学者提供了一个很好的起点,帮助他们理解如何使用Phaser框架创建一个基础的游戏。通过学习如何加载和使用这些资源,你...
此外,还可以利用Phaser的碰撞检测功能,让精灵与其他元素发生交互。 事件处理是Phaser中的另一个重要部分。例如,你可以监听键盘事件,使玩家通过按键控制精灵移动。`Phaser.Input.Keyboard` 类提供了丰富的键盘...
5. Phaser API应用:在实现这些功能时,我们会频繁使用Phaser的API,例如`Phaser.Physics.Arcade`模块进行物理碰撞检测,`Phaser.Group`管理游戏对象,`Phaser.Text`创建分数显示文本,以及`Phaser.SoundManager`...
Phaser是由Photon Storm公司开发的,它提供了丰富的功能,包括精灵、动画、物理引擎、定时器、声音管理等,使开发者能够快速构建交互性强的2D游戏。Phaser支持Canvas和WebGL渲染,可以根据设备性能自动选择最佳方案...
Phaser.js 框架包含了许多功能,如精灵(Sprites)、动画、物理引擎、音频管理、输入处理等,这些都是构建游戏的核心组件。开发者可以利用这些工具快速搭建游戏场景,设计游戏逻辑,并实现交互性。 1. **精灵...