1. 程式人生 > >Java多執行緒之fork/join框架詳解

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類的對新會負責子任務的執行.