Java併發 -- Fork + Join

  1. 線程池+Future: 簡單並行任務
  2. CompletableFuture: 聚合任務
  3. CompletionService: 批量並行任務
  4. Fork/Join: 分治

分治任務模型

  1. 分治任務模型分爲兩個階段:任務分解 + 結果合併
  2. 任務分解 :將任務迭代地分解爲子任務,直至子任務可以 直接計算 出結果
    • 任務和分解後的子任務具有 相似性 (算法相同,只是計算的數據規模不同,往往採用 遞歸 算法)
  3. 結果合併 :逐層合併子任務的執行結果,直至獲得最終結果

Fork/Join

概述

  1. Fork/Join是 並行計算 的框架,主要用來支持分治任務模型,Fork對應任務分解,Join對應結果合併
  2. Fork/Join框架包含兩部分:分治任務 ForkJoinTask + 分治任務線程池 ForkJoinPool
    • 類似於Runnable + ThreadPoolExecutor
  3. ForkJoinTask最核心的方法是 fork 和 join
    • fork:異步地執行一個子任務
    • join:阻塞當前線程,等待子任務的執行結果
  4. ForkJoinTask有兩個子類:RecursiveAction + RecursiveTask
    • Recursive:通過 遞歸 的方式來處理分治任務
    • RecursiveAction.compute:沒有返回值
    • RecursiveTask.compute:有返回值

簡單使用

// 遞歸任務
@AllArgsConstructor
class Fibonacci extends RecursiveTask<Integer> {
    private final int n;

    @Override
    protected Integer compute() {
        if (n <= 1) {
            return n;
        }
        // 創建子任務
        Fibonacci f1 = new Fibonacci(n - 1);
        f1.fork();
        Fibonacci f2 = new Fibonacci(n - 2);
        f2.fork();
        // 等待子任務結果併合並
        return f1.join() + f2.join();
    }
}

// 創建分治任務線程池
ForkJoinPool pool = new ForkJoinPool(4);
// 創建分治任務
Fibonacci fibonacci = new Fibonacci(30);
// 啓動分治任務
System.out.println(pool.invoke(fibonacci)); // 832040

ForkJoinPool的工作原理

  1. Fork/Join並行計算的核心組件是ForkJoinPool
  2. ThreadPoolExecutor本質上是 生產者-消費者 模式的實現
    • 內部有一個 任務隊列 ,該任務隊列是生產者和消費者通信的媒介
    • ThreadPoolExecutor可以有 多個工作線程 ,但這些工作線程都 共享一個任務隊列
  3. ForkJoinPool本質上也是 生產者-消費者 模式的實現,但更加 智能
    • ThreadPoolExecutor內部只有一個任務隊列,而ForkJoinPool內部有 多個任務隊列
    • 當通過invoke或submit 提交任務 時,ForkJoinPool會根據一定的 路由規則 把任務提交到一個任務隊列
      • 如果任務在執行過程中 創建子任務 ,那麼該子任務被會提交到 工作線程對應的任務隊列 中
    • ForkJoinPool支持 任務竊取 ,如果工作線程空閒了,那麼它會竊取其他任務隊列裏的任務
    • ForkJoinPool的任務隊列是 雙端隊列
      • 工作線程 正常獲取任務 和 竊取任務 分別從任務隊列 不同的端 消費,避免不必要的數據競爭

統計單詞數量

@AllArgsConstructor
class MapReduce extends RecursiveTask<Map<String, Long>> {
    private String[] fc;
    private int start;
    private int end;

    @Override
    protected Map<String, Long> compute() {
        if (end - start == 1) {
            return calc(fc[start]);
        } else {
            int mid = (start + end) / 2;
            // 前半部分數據fork一個遞歸任務
            MapReduce mr1 = new MapReduce(fc, start, mid);
            mr1.fork();
            // 後半部分數據在當前任務中遞歸處理
            MapReduce mr2 = new MapReduce(fc, mid, end);
            // 計算子任務,返回合併的結果
            return merge(mr2.compute(), mr1.join());
        }
    }

    // 統計單詞數量
    private Map<String, Long> calc(String line) {
        Map<String, Long> result = new HashMap<>();
        String[] words = line.split("\\s+");
        for (String word : words) {
            if (result.containsKey(word)) {
                result.put(word, result.get(word) + 1);
            } else {
                result.put(word, 1L);
            }
        }
        return result;
    }

    // 合併結果
    private Map<String, Long> merge(Map<String, Long> r1, Map<String, Long> r2) {
        Map<String, Long> result = new HashMap<>(r1);
        r2.forEach((word, count) -> {
            if (result.containsKey(word)) {
                result.put(word, result.get(word) + count);
            } else {
                result.put(word, count);
            }
        });
        return result;
    }
}

String[] fc = {"hello world",
        "hello me",
        "hello fork",
        "hello join",
        "fork join in world"};
ForkJoinPool pool = new ForkJoinPool(3);
MapReduce mapReduce = new MapReduce(fc, 0, fc.length);
Map<String, Long> result = pool.invoke(mapReduce);
result.forEach((word, count) -> System.out.println(word + " : " + count));

小結

  1. Fork/Join並行計算框架主要解決的是 分治任務 ,分治的核心思想是 分而治之
  2. Fork/Join並行計算框架的核心組件是 ForkJoinPool ,支持 任務竊取 ,讓所有線程的工作量基本 均衡
  3. Java 1.8提供的 Stream API 裏的並行流是以ForkJoinPool爲基礎的
    • 默認情況下,所有並行流計算都 共享一個ForkJoinPool ,該共享的ForkJoinPool的線程數是 CPU核數
    • 如果存在 IO密集型 的並行流計算,那可能會因爲一個很慢的IO計算而影響整個系統的 性能
    • 因此,建議 用不同的ForkJoinPool執行不同類型的計算任務

從去年到現在,我根據市場技術棧的需求,整理了一套JAVA的最新教程,如果你現在也在學習Java,在入門學習Java的過程當中缺乏系統的學習教程,你可以加我的Java學習交流羣:【94687,1227】,獲取,羣裏還有學習手冊,面試題,開發工具,PDF文檔教程,可以自行下載。

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