java多線程之fork/join框架詳解

    這個框架的目的主要是更好地利用底層平臺上的多核CPU和多處理器來進行處理,解決問題時通常使用分治算法或map/reduce算法來進行.這個框架的名稱來源於使用時的兩個基本操作fork和join,可以類比於map/reduce中的map和reduce操作.fork操作的作用是把一個大的問題劃分成若干個較小的問題.這個劃分過程一般是遞歸進行的,直到得到可以直接進行計算的粒度合適的子問題.在劃分時,需要恰當地選取子問題的大小.太大的子問題不利於通過並行方式來提高性能,而太小的子問題則會帶來較大的額外開銷.每個子問題在計算完成之後,可以得到關於整個問題的部分解.join操作的作用是把這些部分解收集並組織起來,得到最終的完整解.調用join操作的過程也可能是遞歸進行的,於fork操作相對應.


    相對於一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務的處理方式上.在一般的線程池中,如果一個線程正在執行的任務由於某些原因無法繼續運行,那麼該線程會處於等待狀態.而在fork/join框架實現中,如果某個子問題由於等待另外一個子問題的完成而無法繼續運行.那麼處理該子問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式減少了線程的等待時間,提高了性能.爲了fork/join框架能夠高效運行,在每個子問題的實現中應該避免使用synchronized關鍵字或其他方式來進行同步,也不應該使用阻塞式I/O操作或過多地訪問共享變量.在理想情況下,每個子問題的實現中都應該只進行CPU相關的計算,並且只使用每個問題的內部對象.唯一的同步應該只發生在子問題和創建它的父問題之間.


     一個fork/join框架執行的任務由ForkJoinTask類表示.ForkJoinTask類實現了Future接口,可以按照Future接口的方式來使用.在ForkJoinTask類中最重要的兩個方法是fork和join,其中fork方法用來以異步方式啓動任務的執行,而join方法則等待任務完成並返回執行結果.在創建自己的任務時,最好不要直接繼承自ForkJoinTask類,而要繼承自ForkJoinTask類的子類RecursiveTask或RecursiveAction類.兩者的區別在於RecursiveTask類表示的任務可以返回結果,而RecursiveAction類不行.


     在fork/join框架中,任務的執行由ForkJoinPool類的對象來完成.ForkJoinPool類實現了ExecutorService接口,除了執行ForkJoinTask類的對新外,還可以使用一般的Callable和Runnable接口來表示的任務,在ForkJoinPool類的對新中執行的任務大致可以分成兩類:一類是通過execute,invoke或submit方法直接提交的任務;另外一類是ForkJoinTask類的對新在執行過程中產生的子任務,並通過fork方法來運行.一般的做法是表示整個問題的ForkJoinTask類的對象用第一類形式提交,而在執行過程中產生的子任務並不需要進行處理,ForkJoinPool類的對新會負責子任務的執行.

import java.io.File;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ForkJoinPool;

import java.util.concurrent.ForkJoinTask;

import java.util.concurrent.RecursiveTask;

  

/**

 * <pre>

 * 輕量級任務執行框架fork/join詳解,使用該框架計算文件目錄大小

 * </pre>

 * User: ketqi

 * Date: 2013-01-27 17:40

 */

public class ForkJoinDemo {

    private static class CalculateTask extends RecursiveTask<Long> {

        final File file;

        public CalculateTask(final File theFile) {

            file = theFile;

        }

        @Override

        public Long compute() {

            long size = 0;

            if (file.isFile()) {

                size = file.length();

            } else {

                final File[] children = file.listFiles();

                if (children != null) {

                    List<ForkJoinTask<Long>> taskList = new ArrayList<ForkJoinTask<Long>>();

                    for (final File child : children) {

                        if (child.isFile()) {

                            size += child.length();

                        } else {

                            taskList.add(new CalculateTask(child));

                        }

                    }

                    //invokeAll方法循環調用task.fork()執行子任務.

                    for (final ForkJoinTask<Long> task : invokeAll(taskList)) {

                        //task.join()方法等待任務完成並返回執行的結果

                        size += task.join();

                    }

                }

            }

            return size;

        }

    }

    public static void main(String[] args) {

        long start = System.nanoTime();

        long total = new ForkJoinPool().invoke(new CalculateTask(new File("E:\\workspace\\java7")));

        long end = System.nanoTime();

        System.out.println("Total Size: " + total + "B");

        System.out.println("Time taken: " + (end - start) / 1.0e9);

    }

}


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