Phaser是一个可重用同步屏障,类似于CyclicBarrier、CountDownLatch,但是使用起来更灵活。
A reusable synchronization barrier, similar in functionality to * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and * {@link java.util.concurrent.CountDownLatch CountDownLatch} * but supporting more flexible usage. <p><b>Registration.</b> Unlike the case for other barriers, the * number of parties <em>registered</em> to synchronize on a phaser * may vary over time. Tasks may be registered at any time (using * methods {@link #register}, {@link #bulkRegister}, or forms of * constructors establishing initial numbers of parties), and * optionally deregistered upon any arrival (using {@link * #arriveAndDeregister}). As is the case with most basic * synchronization constructs, registration and deregistration affect * only internal counts; they do not establish any further internal * bookkeeping, so tasks cannot query whether they are registered. * (However, you can introduce such bookkeeping by subclassing this * class.)
Phaser主要接口如下
- arriveAndAwaitAdvance() 当前线程当前阶段执行完毕,等待其它线程完成当前阶段。如果当前线程是该阶段最后一个未到达的,则该方法直接返回下一个阶段的序号(阶段序号从0开始),同时其它线程的该方法也返回下一个阶段的序号。
- arriveAndDeregister() 该方法立即返回下一阶段的序号,并且其它线程需要等待的个数减一,并且把当前线程从之后需要等待的成员中移除。如果该Phaser是另外一个Phaser 的子Phaser(层次化Phaser会在后文中讲到),并且该操作导致当前Phaser的成员数为0,则该操作也会将当前Phaser从其父 Phaser中移除。
- arrive() 该方法不作任何等待,直接返回下一阶段的序号。
- awaitAdvance(int phase) 该方法等待某一阶段执行完毕。如果当前阶段不等于指定的阶段或者该Phaser已经被终止,则立即返回。该阶段数一般由arrive()方法或者arriveAndDeregister()方法返回。返回下一阶段的序号,或者返回参数指定的值(如果该参数为负数),或者直接返回当前阶段序号(如果当前Phaser已经被终止)。
- awaitAdvanceInterruptibly(int phase) 效果与awaitAdvance(int phase)相当,唯一的不同在于若该线程在该方法等待时被中断,则该方法抛出InterruptedException。
- awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit) 效果与awaitAdvanceInterruptibly(int phase)相当,区别在于如果超时则抛出TimeoutException。
- bulkRegister(int parties) 注册多个party。如果当前phaser已经被终止,则该方法无效,并返回负数。如果调用该方法时,onAdvance方法正在执行,则该方法等待其执行完毕。如果该Phaser有父Phaser则指定的party数大于0,且之前该Phaser的party数为0,那么该Phaser会被注册到其父Phaser中。
- forceTermination() 强制让该Phaser进入终止状态。已经注册的party数不受影响。如果该Phaser有子Phaser,则其所有的子Phaser均进入终止状态。如果该Phaser已经处于终止状态,该方法调用不造成任何影响。
玩具代码
import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; //Phaser类提供的同步线程机制是在每个步骤的末端, 所以全部的线程都完成第一步后,才能开始执行第二步。 public class FileSearch implements Runnable { private String initPath; private String end; private List<String> results; private Phaser phaser; public FileSearch(String initPath,String end,Phaser phaser){ this.initPath = initPath; this.end = end; this.phaser = phaser; results = new ArrayList<>(); } //根据目录查找文件 private void directoryProcess(File file){ File list[] = file.listFiles(); if(list != null){ for (int i = 0; i < list.length; i++) { if(list[i].isDirectory()){ directoryProcess(list[i]); }else{ fileProcess(list[i]); } } } } //记录文件 private void fileProcess(File file){ if(file.getName().endsWith(end)){ results.add(file.getAbsolutePath()); } } //过滤超过24小时的数据 private void filterResults(){ List<String> newResults = new ArrayList<>(); long actualDate = new Date().getTime(); for(int i=0;i<results.size();i++){ File file = new File(results.get(i)); long fileDate = file.lastModified(); if(actualDate-fileDate < TimeUnit.MICROSECONDS.convert(1, TimeUnit.DAYS)){ newResults.add(results.get(i)); } } results = newResults; } private boolean checkResults(){ //检查文件列表 if(results.isEmpty()){ System.out.printf("%s: Phase %d: 0 results.\n", Thread.currentThread().getName(),phaser.getPhase()); System.out.printf("%s: Phase %d: 0 End.\n", Thread.currentThread().getName(),phaser.getPhase()); //通知phaser,当前工作已经完成,并且在不参与下一个阶段的工作。 phaser.arriveAndDeregister(); return false; }else{ System.out.printf("%s: Phase %d: 0 results.\n", Thread.currentThread().getName(),phaser.getPhase()); //通知phaser,当前工作已经完成,并且在等待其他线程完成。 phaser.arriveAndAwaitAdvance(); return true; } } private void showInfo(){ for (int i = 0; i < results.size(); i++) { File file = new File(results.get(i)); System.out.printf("%s: %s\n", Thread.currentThread().getName(), file.getAbsolutePath()); } phaser.arriveAndAwaitAdvance(); } @Override public void run() { phaser.arriveAndAwaitAdvance(); System.out.printf("%s:Starting.\n", Thread.currentThread().getName()); File file = new File(initPath); if(file.isDirectory()){ directoryProcess(file); } if(!checkResults()){ return; } filterResults(); if(!checkResults()){ return; } showInfo(); phaser.arriveAndDeregister(); System.out.printf("%s:Work completed.\n", Thread.currentThread().getName } public static void main(String[] args) { Phaser phaser = new Phaser(3); FileSearch system = new FileSearch("C:\\Windows","log",phaser); FileSearch apps = new FileSearch("C:\\Program Files","log",phaser); FileSearch documents = new FileSearch("C:\\Documents And Settings","log",phaser); Thread systemThread = new Thread(system,"system"); systemThread.start(); Thread appsThread = new Thread(apps,"apps"); appsThread.start(); Thread documentsThread = new Thread(documents,"documents"); documentsThread.start(); //等待三个线程结束 try{ systemThread.join(); appsThread.join(); documentsThread.join(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.printf("Terminated:%s", phaser.isTerminated()); } }