同步辅助类Phaser

Phaser是一个可以重复利用的同步屏障,功能上与CyclicBarrier和CountDownLatch相似,不过提供更加灵活的用法。也就是说,Phaser的同步模型与它们差不多。一般运用的场景是一组线程希望同时到达某个执行点后(先到达的会被阻塞),执行一个指定任务,然后这些线程才被唤醒继续执行其它任务。
Phaser一般是定义一个parties(参与方)数(parties一般代指需要进行同步的线程),当这些parties到达某个执行点,就会调用await方法,表示到达某个阶段(phase),然后就会阻塞直到有足够的parites数(也就是线程数)都调用过await方法后,这些线程才会被逐个唤醒,另外,在唤醒之前,可以选择性地执行某个定制的任务。Phaser对比起CyclicBarrier,不仅它是可以重复同步,并且parties数是可以动态注册的,另外还提供了非阻塞的arrive方法表示先到达阶段等,大大提高了同步模型的灵活性,当然了,实现也会相对复杂。

注册(Registration)

和其它屏障不一样,在phaser上进行同步注册的parites数可能会随着时间改变而不同。可以在任何时间注册任务(调用register,bulkRegister方法,或者可以初始化parties数的构造函数形式),以及能够在到达之后可选择地撤销(使用arriveAndDeregister方法)。像大多数基本的同步工具一样,注册和撤销只会影响内部的计数,他们不会在内部保留对注册对象的跟踪,所以任务不能通过查询得知自身是否被注册。(然而,你能够引入类似的跟踪策略通过扩展这个类)。

同步(Synchronization)

就像CyclicBarrier一样,Phaser可以重复地等待。arriveAndAwaitAdvance方法与CyclicBarrier.await作用类似。每一代(generation)的phaser有一个关联的阶段号(phase number)。阶段号从0开始,当所有parties都到达阶段的时候就会加一,直到Integer.MAX_VALUE后返回0。阶段号的使用允许在到达某个阶段以及在等待其它parites的时候,通过以下两类可以被任何注册过的party调用的方法,执行单独的操作:

  • 到达(Arrival):arrive方法和arriveAndDeregister方法记录到达。这些方法不会阻塞,但会返回一个关联的到达阶段号(arrival phase number),也就是,phaser在到达以后所用的阶段号。当最后的party到达一个给定的阶段,就可以执行可选的操作,并且阶段号自加一。这些操作都会被触发阶段增加的party执行,并且会被可重写方法onAdvance(同时管理Phaser的终结)安排管理。重写onAdvance方法比起CyclicBarrier提供的栅栏操作很相似,但更加灵活。
  • 等待(Waiting):awaitAdvance方法需要一个表示到达阶段号的参数,并在phaser增加到(或者已经在)不同的阶段的时候返回。与CyclicBarrier类似结构不同,awaitAdvance方法会在等待线程被中断的时候继续等待。当然也有可中断和超时版本,但是当任务等待发生中断或者超时遇到的异常也不会改变phaser的状态。如果必要,你可以在这些异常的处理器里执行关联的恢复操作,一般是在调用forceTermination之后恢复。Phaser可能也会被执行在ForkJoinPool中的任务使用,这样当其它线程在等待phaser增加被阻塞的时候,就可以确保有效平行地执行任务。

终结(Termination)

phaser可能进入一个终结状态,可以通过isTerminated来检查。当终结的时候,所有的同步方法都不会在等待下一个阶段而直接返回,返回一个负值来表示该状态。类似地,在终结的时候尝试注册没有任何效果。当onAdvance调用返回true的时候就会触发终结。onAdvance默认实现为当一个反注册导致注册parties数降为0的时候返回true。当phser要控制操作在一个固定得迭代次数时,就可以很方便地重写这个方法,当当前阶段号到达阀值得时候就返回true导致终结。forceTermination方法也时另一个可以突然释放等待线程并且允许它们终结。

分层(Tiering)

通过构造树结构从而降低竞争。一个拥有大量参与者的Phaser能够通过构造拥有同一个公共父Phaser的结构来降低严重的同步竞争开销。这样能够极大地增加吞吐量,即使它带来每个操作更大的开销。

在一个分层phasers的树结构中,注册和撤销孩子phasers以及它们的父phaser是被自动管理的。当一个子phaser的注册数变为非0时(通过Phaser(Phaser,int)、constructor、register、bulkRegister),子phaser被父phaser注册。当注册数变为0,子phaser会从父phaser中撤销。

监控(Monitoring)

同步方法只能被注册的parties调用时,phaser的当前状态可以被任何调用者监控。在任何时刻,有getRegisteredParties总共的parties,其中,有getArrivedParties个parites到达getPhase的当前阶段。当剩下getUnarrivedParties个parties到达,phase增加。这些方法的返回值可能反映短暂的状态,因此一般在同步控制中不太有用。toString方法以一种可以方便信息监控的格式返回这些状态的快照。

相关问题

  1. Phaser什么时候终止? A:调用arriveAndDeregister()使注册参与方降为0时或调用forceTermination()。
  2. 如何控制Phaser执行的阶段数?A:通过覆盖onAdvance( ) 方法。
  3. Phaser中最大的注册party数目?A:65535
  4. Phaser在现实世界中的使用场景?A:软件开发可以通过Phaser来管理;如第一阶段收集需求,第二阶段软件开发,第三阶段测试。

results matching ""

    No results matching ""