併發多階段任務的執行——Phaser


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章