線程并發工具類之Fork-Join框架

Fork-Join框架

分治法

分治算法的基本思想將一個規模為N的問題,分解成K個規模較小的子問題,這些子問題相互獨立且月原問題性質相同。求解出子問題的解,合并得到原問題的解。

Fork-Join框架

任務分隔:體現了分而治之的思維,將一個大任務,進行拆分(Fork)成分成若干個小任務(拆到不能拆分為止)
執行任務并合并結果:分割的子任務分別放在雙端隊列中,然后啟動多個線程分別從雙端隊列中獲取子任務并執行,子任務完成后的結果放到另外一個里,啟動一個線程從這個隊列里取數據計算后返回

image.png
Fork-Join框架使用標準范式
  • ForkJoinTask:創建ForkJoinTask任務,該類提供了fork()、join()機制,通常繼承它的RecursiveTask、RecursiveAction抽象類,RecursiveTask用于返回值任務,RecursiveAction用于無返回值任務
  • ForkJoinPool:創建ForkJoinPool對象,用于執行ForkJoinTask任務
  • 拆分任務并提交到上一級Task
  • ForkJoinPool池invoke任務
  • join所有的之任務結果
工作密取

多線程操作雙端隊列,每個消費者都有各自的雙端隊列。如果一個消費者完成了自己雙端隊列中的全部工作,那么它可以從其它消費者雙端隊列末尾秘密地獲取工作。

任務分割后的子任務會添加到當前線程所維護的雙端隊列中,進入隊列頭部,當一個工作線程的隊列任務暫時沒有時,會隨機從其他工作線程的雙端隊列尾部獲取一個任務執行
Fork-Join框架同步返回計算數組求和
import java.util.concurrent.RecursiveTask;

import com.shawntime.enjoy.architect.concurrency.SleepUtils;

public class ArraySumTask extends RecursiveTask<Long> {

    private int[] array;

    private int startIndex;

    private int endIndex;

    private int minNum;

    public ArraySumTask(int[] array, int startIndex, int endIndex, int minNum) {
        this.array = array;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
        this.minNum = minNum;
    }

    @Override
    protected Long compute() {
        if (endIndex - startIndex < minNum) {
            // 已經是最小了
            Long result = 0L;
            for (int i = startIndex; i <= endIndex; ++i) {
                SleepUtils.sleepByMilliSeconds(1);
                result += array[i];
            }
            return result;
        } else {
            System.out.println("繼續拆分....");
            // 繼續拆分
            int middle = (endIndex + startIndex) / 2;
            ArraySumTask leftTask = new ArraySumTask(array, startIndex, middle, minNum);
            ArraySumTask rightTask = new ArraySumTask(array, middle + 1, endIndex, minNum);
            // 提交任務
            invokeAll(leftTask, rightTask);
            return leftTask.join() + rightTask.join();
        }
    }
}
int[] array = ArrayUtils.makeArray(arrayLength);
ForkJoinPool forkJoinPool = new ForkJoinPool();
int minNum = arrayLength / 50;
ForkJoinTask<Long> task = new ArraySumTask(array, 0, array.length - 1, minNum);
forkJoinPool.invoke(task);
Long value = task.join();
Fork-Join框架異步遍歷查找文件
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveAction;

/**
 * 異步的方式不帶返回值
 */
public class FindFileTask extends RecursiveAction {

    private File file;

    public FindFileTask(File file) {
        this.file = file;
    }

    @Override
    protected void compute() {
        if (file == null) {
            return;
        }
        File[] files = file.listFiles();
        List<FindFileTask> tasks = new ArrayList<>();
        for (File subFile : files) {
            if (subFile.isDirectory()) {
                FindFileTask task = new FindFileTask(subFile);
                tasks.add(task);
            } else {
                if (subFile.getName().endsWith("mp4")) {
                    System.out.println(subFile.getAbsolutePath());
                }
            }
        }
        if (tasks.isEmpty()) {
            return;
        }
        for (FindFileTask task : invokeAll(tasks)) {
            task.join();
        }
    }
}
public static void main(String[] args) {
    ForkJoinPool forkJoinPool = new ForkJoinPool();
    File file = new File("D:/");
    FindFileTask findFiles = new FindFileTask(file);
    // 異步提交
    forkJoinPool.execute(findFiles);

    int result = 0;
    for (int i = 0; i < 1000; ++i) {
        result += i;
    }

    System.out.println("main result : " + result);

    findFiles.join(); // 阻塞

    System.out.println("end....");
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容