天天看點

多線程 ForkJoinPool使用

背景:ForkJoinPool的優勢在于,可以充分利用多cpu,多核cpu的優勢,把一個任務拆分成多個“小任務”,把多個“小任務”放到多個處理器核心上并行執行;當多個“小任務”執行完成之後,再将這些執行結果合并起來即可。這種思想值得學習。

主要參考《瘋狂java講義》

回到頂部

使用

Java7 提供了ForkJoinPool來支援将一個任務拆分成多個“小任務”并行計算,再把多個“小任務”的結果合并成總的計算結果。

ForkJoinPool是ExecutorService的實作類,是以是一種特殊的線程池。

使用方法:建立了ForkJoinPool執行個體之後,就可以調用ForkJoinPool的submit(ForkJoinTask<T> task) 或invoke(ForkJoinTask<T> task)方法來執行指定任務了。

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

下面的UML類圖顯示了ForkJoinPool、ForkJoinTask之間的關系:

多線程 ForkJoinPool使用

舉例

以還行沒有傳回值的“大任務”(簡單低列印1~300的數值)為例,程式将一個“大任務”拆分成多個“小任務”,并将任務交給ForkJoinPool來執行

/**
 * Project Name:Spring0725
 * File Name:ForkJoinPoolAction.java
 * Package Name:work1201.basic
 * Date:2017年12月4日下午2:26:55
 * Copyright (c) 2017, 深圳金融電子結算中心 All Rights Reserved.
 *
*/

package work1201.basic;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

/**
 * ClassName:ForkJoinPoolAction <br/>
 * Function: 使用ForkJoinPool完成一個任務的分段執行
 * 簡單的列印0-300的數值。用多線程實作并行執行
 * Date:     2017年12月4日 下午2:26:55 <br/>
 * @author   prd-lxw
 * @version   1.0
 * @since    JDK 1.7
 * @see      
 */
public class ForkJoinPoolAction {
    
    public static void main(String[] args) throws Exception{
        PrintTask task = new PrintTask(0, 300);
        //建立執行個體,并執行分割任務
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(task);
         //線程阻塞,等待所有任務完成
        pool.awaitTermination(2, TimeUnit.SECONDS);
        pool.shutdown();
    }
}

/**
 * ClassName: PrintTask <br/>
 * Function: 繼承RecursiveAction來實作“可分解”的任務。
 * date: 2017年12月4日 下午5:17:41 <br/>
 *
 * @author prd-lxw
 * @version 1.0
 * @since JDK 1.7
 */
class PrintTask extends RecursiveAction{
    private static final int THRESHOLD = 50; //最多隻能列印50個數
    private int start;
    private int end;
    
    

    public PrintTask(int start, int end) {
        super();
        this.start = start;
        this.end = end;
    }



    @Override
    protected void compute() {
        
        if(end - start < THRESHOLD){
            for(int i=start;i<end;i++){
                System.out.println(Thread.currentThread().getName()+"的i值:"+i);
            }
        }else {
            int middle =(start+end)/2;
            PrintTask left = new PrintTask(start, middle);
            PrintTask right = new PrintTask(middle, end);
            //并行執行兩個“小任務”
            left.fork();
            right.fork();
        }
        
    }
    
}      

繼續閱讀