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