Java併發編程——ForkJoinPool實戰演練

ForkJoinPool體現了分而治之的思想,將一個大事件,拆分成若干個小事件去處理,執行完成後,再將一個個小事件執行的結果合併到一起。

使用方法:

1、創建ForkJoinPool實例

2、通過submit方法、invoke方法、invokeAll方法來執行指定任務。

  • T invoke(ForkJoinTask<T> task)執行給定的任務,在完成後返回其結果。
  • List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)執行給定的任務,返回持有他們的狀態和結果的所有完成的任務列表。
  • ForkJoinTask<T> submit(Callable<T> task)提交併執行,並返回任務處理結果的Future。  
  • ForkJoinTask<T> submit(ForkJoinTask<T> task)提交一個ForkJoinTask來執行。  
  • ForkJoinTask<?> submit(Runnable task)提交一個可運行的任務執行,並返回一個表示該任務的結果。  
  • ForkJoinTask<T> submit(Runnable task, T result)提交一個可運行的任務執行,並返回一個表示該任務的結果。

3、ForkJoinTask:代表一個可以並行、合併的任務。ForkJoinTask是一個抽象類,它還有兩個抽象子類:RecusiveAction和RecusiveTask。其中RecusiveTask代表有返回值的任務,而RecusiveAction代表沒有返回值的任務。

代碼演示(此處只演示有返回值的情況):

package com.alex.fork;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 *  搜索指定文件信息
 *  @author: alex
 *  @Date:  2019/3/20 9:52
 *  @Description: 演示RecursiveTask的用法,將大事件拆分成若干個小任務去執行,執行完成後使用ForkJoinPool,合併結果集
 *  場景描述:搜索指定文件名,獲得該文件名所在的目錄。
 *  將每一層的文件夾都當做一個子任務進行拆分,尋找每個子文件夾中的內容,最後合併結果集。
 */
public class SearchFiles extends RecursiveTask<String> {

    private File path;
    private String searchFileName;

    /**
     * 構造方法
     * @param path 文件信息
     * @param searchFileName 目標文件名字
     */
    public SearchFiles(File path, String searchFileName) {
        this.path = path;
        this.searchFileName = searchFileName;
    }

    /**
     * 重新compute方法
     * @return 結果
     */
    @Override
    protected String compute() {
        String filePath = "";  //存放文件路徑
        List<SearchFiles> subTask = new ArrayList<SearchFiles>(); //子任務集合
        File[] files = path.listFiles();
        for (File file : files) {
            //判斷是否是文件夾,如果是,則添加到子任務集合中,不是,則判斷是否是目標文件
            if (file.isDirectory()) {
                subTask.add(new SearchFiles(file, searchFileName));
            } else {
                if (file.getName().equals(searchFileName)) { //是否是目標文件
                    filePath = file.getAbsolutePath(); //返回目標文件路徑
                }
            }
        }
        //判斷子任務集合是否爲空
        if (!subTask.isEmpty()) {
            //通過invokeAll方法,執行所有子任務
            for (SearchFiles task : invokeAll(subTask)) {
                if (!task.join().isEmpty()) {
                    filePath = filePath + task.join() + ",";
                }
            }
        }
        return filePath;
    }

    /**
     * 搜索目標文件
     * @param path 文件路徑
     * @param fileName 目標文件名稱
     * @return 目標文件路徑集合
     */
    public static List<String> searchFileByName(String path, String fileName) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SearchFiles findDirFiles = new SearchFiles(new File(path), fileName);
        forkJoinPool.invoke(findDirFiles);
        String result = findDirFiles.join();
        List<String> resultList = new ArrayList<>();
        if (!result.isEmpty()) {
            for (String name : result.split(",")) {
                if (!name.isEmpty()) {
                    resultList.add(name);
                }
            }
        }
        return resultList;
    }
}

 測試類:

package com.alex.fork;

import java.util.List;

/**
 * 搜索指定文件的測試方法
 */
public class SearchFilesTest {
    public static void main(String[] args) {
        List<String> list = SearchFiles.searchFileByName("F:\\106other", "下載說明.txt");
        list.forEach(System.out::println);
//        for (String s : list) {
//            System.out.println(s);
//        }
    }

}

 運行結果:

F:\106other\visualvm-ml\下載說明.txt
F:\106other\推薦人簡歷\下載說明.txt

 

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