java併發API從java7提供了併發多階段任務的抽象Phaser。如果我們有併發任務且需要分段執行的時候
我們可以考慮Phaser這個類。
Phaser有一個特別的地方,即不需要處理InterruptedException除了(awaitAdvanceInterruptibly(int phaser)方法)
我們模擬一種場景:
我們有三個任務,分別從三個不同的文件夾及其子文件夾查找過去24小時內修改過的擴展名
爲.log的文件。這三個任務分別包含以下三個步驟:
1、在指定的文件夾下篩選出擴展名爲.log的文件;
2、對第一步的結果進行過濾,去除修改時間超過24小時的文件;
3、將結果打印至控制檯;
我們藉助Phaser完成個任務的定義。
我們定義了兩個類:
FileSearcher
Core
FileSearcher是任務的執行類;
Core是程序的入口
代碼如下:
package com.ali.concurrency.phaser;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
public class FileSearcher implements Runnable{
private final String dir;
private final String end;
private List<File> results = new ArrayList<File>();
private final Phaser controller;
public FileSearcher(String dir, String end, Phaser controller){
this.dir = dir;
this.end = end;
this.controller = controller;
}
@Override
public void run() {
<u>controller.arriveAndAwaitAdvance();</u>
System.out.println(Thread.currentThread().getName() + "start...");
File root = new File(dir);
if(root.isDirectory()){
dirProcess(dir);
}
if(!checkResult()) return;
filterFile();
if(!checkResult()) return;
showInfo();
<u>controller.arriveAndDeregister();</u>
System.out.println(Thread.currentThread().getName() + " Work comeleted.");
}
private void showInfo(){
for(File f : results){
System.out.println(Thread.currentThread().getName() + " : " + f.getAbsolutePath());
}
<u>controller.arriveAndAwaitAdvance();</u>
}
private boolean checkResult(){
if(results.size() == 0){
System.out.println(Thread.currentThread().getName() + " Phaser " + controller.getPhase() + " : 0 results");
System.out.println(Thread.currentThread().getName() + " Phaser " + controller.getPhase() + " : End ");
<u>controller.arriveAndDeregister();</u>
return false;
}else{
System.out.println(Thread.currentThread().getName() + " Phaser " + controller.getPhase() + " : " + results.size() + "results");
<u>controller.arriveAndAwaitAdvance();</u>
return true;
}
}
private void dirProcess(String dir){
<u>controller.arriveAndAwaitAdvance();</u>
File dirFile = new File(dir);
File[] dirFileArr = dirFile.listFiles();
for(int i = 0; i < dirFileArr.length; i ++){
if(dirFileArr[i].isFile()){
fileProcess(dirFileArr[i]);
}else if(dirFileArr[i].isDirectory()){
dirProcess(dirFileArr[i].getPath());
}
}
}
private void fileProcess(File f){
if(f.getName().endsWith(end)){
results.add(f);
}
}
private void filterFile(){
List<File> newResults = new ArrayList<File>();
Date now = new Date();
for(File f : results){
if(f.lastModified() - now.getTime() < TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS)){
newResults.add(f);
}
}
results = newResults;
}
}
package com.ali.concurrency.phaser;
import java.util.concurrent.Phaser;
public class Core {
public static void main(String[] args){
Phaser controller = new Phaser(3);
FileSearcher system = new FileSearcher("C:\\testfile\\1", "log", controller);
FileSearcher apps = new FileSearcher("C:\\testfile\\2", "log", controller);
FileSearcher documents = new FileSearcher("C:\\testfile\\3", "log", controller);
Thread systemThread = new Thread(system,"System");
Thread appsThread = new Thread(apps,"apps");
Thread documentsThread = new Thread(documents,"documents");
systemThread.start();
appsThread.start();
documentsThread.start();
try{
systemThread.join();
appsThread.join();
documentsThread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Terminated: " + controller.isTerminated());
}
}
documentsstart...
appsstart...
Systemstart...
documents Phaser 2 : 0 results
documents Phaser 2 : End
apps Phaser 2 : 0 results
apps Phaser 2 : End
System Phaser 2 : 4results
System Phaser 3 : 4results
System : C:\testfile\1\1_333.log
System : C:\testfile\1\1_456.log
System : C:\testfile\1\1_666.log
System : C:\testfile\1\1_777.log
System Work comeleted.
Terminated: true
我們從run方法中理邏輯:
程序先在第一階段等待,目的是等待所有線程開始;
然後執行dirProcess篩選出.log類型的文件,然後checkResult
接着filterFile過濾掉空結果的任務
然後checkResult
接着showInfo,其中showInfo在打印後再次等待
接着任務從phaser中註銷
打印終止信息爲true。
一個Phaser有兩種狀態:
1、活躍態(Active),當存在參與同步的線程的時候,Phaser就是活躍的,並且在每個階段結束的時候進行同步。
在這種狀態中,Phaser的執行如前文所述。
2、終止態(Termination),當所有參與同步的線程都取消註冊的時候,Phaser就處於終止態。在這種狀態下Phaser沒有任何參與者。
更具體的說,當onAdvance()方法返回true的時候,就處於了終止態。通過覆蓋這個方法可以改變默認的行爲。當Phaser處於
終止態的時候,同步方法arriveAndAwaitAdvance()方法會立即返回,而且不會做任何的同步操作。
其他方法請參考java7API