標籤:
fork-join架構
fork操作的作用是把一個大的問題劃分成若干個較小的問題。在這個劃分過程一般是遞迴進行的。直到可以直接進行計算。需要恰當地選取子問題的大小。太大的子問題不利於通過並行方式來提高效能,而太小的子問題則會帶來較大的額外開銷。每個子問題計算完成後,可以得到關於整個問題的部分解。join操作的作用是把這些分解手機組織起來,得到完整解。
在fork/join架構中,若某個子問題由於等待另一個子問題的完成而無法繼續執行。那麼處理該子問題的線程會主動尋找其他尚未運行完成的子問題來執行。這種方式減少了線程的等待時間,提高了效能。子問題中應該避免使用synchronized關鍵詞或其他方式方式的同步。也不應該是一阻塞IO或過多的訪問共用變數。在理想情況下,每個子問題的實現中都應該只進行CPU相關的計算,並且只適用每個問題的內部對象。唯一的同步應該只發生在子問題和建立它的父問題之間。
Fork/Join架構的主要類
一個fork/join架構之下的任務由ForkJoinTask類表示。ForkJoinTask實現了Future介面,可以按照Future介面的方式來使用。在ForkJoinTask類中之重要的兩個方法fork和join。fork方法用以一部方式啟動任務的執行,join方法則等待任務完成並返回指向結果。在建立自己的任務是,最好不要直接繼承自ForkJoinTask類,而要繼承自ForkJoinTask類的子類RecurisiveTask或RecurisiveAction類。兩種的區別在於RecurisiveTask類表示的任務可以返回結果,而RecurisiveAction類不行。
fork/join架構任務的執行由ForkJoinTask類的對象之外,還可以使用一般的Callable和Runnable介面來表示任務。在ForkJoinPool類的對象中執行的任務大支可以分為兩類,一類通過execute、invoke或submit提交的任務;另一類是ForkJoinTask類的對象在執行過程中產生的子任務,並通過fork方法來運行。一般的做法是表示整個問題的ForkJoinTask類的對象用第一類型是提交,而在執行過程中產生的子任務並不需要進行處理,ForkJoinPool類對象會負責子任務的執行。
ForkJoinPool是ExecutorService的實作類別,因此是一種特殊的線程池。使用方法與Executor架構類似。ForkJoinPool提供如下兩個常用的構造器:
ForkJoinPool(int parallelism) 建立一個包含parallelism個並行線程的ForkJoinPool。
ForkJoinPool() 以Runtime.availableProcessors()方法的傳回值作為parallelism參數來建立ForkJoinPool。
ForkJoinPool有如下三個方法啟動線程:
使用ForkJoinPool的submit(ForkJoinTask task) 或 invoke(ForkJoinTask task) 方法來執行指定任務。其中ForkJoinTask代表一個可以並行、合并的任務。
| |
用戶端非fork/join調用 |
內部調用fork/join |
| 非同步執行 |
execute(ForkJoinTask) |
ForkJoinTask.fork |
| 等待擷取結果 |
invoke(ForkJoinTask) |
ForkJoinTask.invoke |
| 執行,擷取Future |
submit(ForkJoinTask) |
ForkJoinTask.fork(ForkJoinTask are Futures) |
ForkJoinTask是分支合并的執行任何,分支合并的商務邏輯使用者可以再繼承了這個抽先類之後,在抽象方法exec()中實現。其中exec()的返回結果和ForkJoinPool的執行調用方(execute(...),invoke(...),submit(...)),共同決定著線程是否阻塞,具體請看下面的測試案例。
ForkJoinTask 是一個抽象類別,它還有兩個抽象子類:RecurisiveTask和RecurisiveAction。
RecurisiveTask代表有傳回值的任務。RecursiveTask<T>是泛型類。T是傳回值的類型。
RecurisiveAction代表沒有傳回值的任務。
異常處理
ForkJoinTask在執行的時候可能會拋出異常,但是沒辦法在主線程裡直接捕獲異常,所以ForkJoinTask提供了isCompletedAbnormally()方法來檢查任務是否已經拋出異常或已經被取消了,並且可以通過ForkJoinTask的getException方法擷取異常。使用如下代碼:
if(task.isCompletedAbnormally()) { System.out.println(task.getException());}
getException方法返回Throwable對象,如果任務被取消了則返回CancellationException。如果任務沒有完成或者沒有拋出異常則返回null。
Java Fork/Join架構