Java中的Fork/Join框架使用詳解
意義
Fork/Join 框架:就是在必要的情況下,將一個大任務(wù),進行 拆分(fork)成若干個小任務(wù)(拆到不可再拆時),再將一個個 的小任務(wù)運算的結(jié)果進行 join 匯總
Fork/Join 框架與傳統(tǒng)線程池的區(qū)別
采用 “工作竊取”模式(work-stealing): 當(dāng)執(zhí)行新的任務(wù)時它可以將其拆分分成更小的任務(wù)執(zhí)行, 并將小任務(wù)加到線程隊列中,然后再從一個隨機線程的隊 列中偷一個并把它放在自己的隊列中。
相對于一般的線 程池實現(xiàn),fork/join框架的優(yōu)勢體現(xiàn)在對其中包含的任務(wù)的 處理方式上.在一般的線程池中,如果一個線程正在執(zhí)行的 任務(wù)由于某些原因無法繼續(xù)運行,那么該線程會處于等待 狀態(tài)、
而在fork/join框架實現(xiàn)中,如果某個子問題由于等 待另外一個子問題的完成而無法繼續(xù)運行.那么處理該子 問題的線程會主動尋找其他尚未運行的子問題來執(zhí)行.這 種方式減少了線程的等待時間,提高了性能.
使用
ForkJoinTask:我們要使用 Fork/Join 框架,首先需要創(chuàng)建一個 ForkJoin 任務(wù)。
該類提供了在任務(wù)中執(zhí)行 fork 和 join 的機制。通常情況下我們不需要直接集成 ForkJoinTask 類,只需要繼承它的子類,
- RecursiveAction:用于沒有返回結(jié)果的任務(wù)
- RecursiveTask:用于有返回結(jié)果的任務(wù)
- ForkJoinPool:ForkJoinTask 需要通過 ForkJoinPool 來執(zhí)行
- RecursiveTask: 繼承后可以實現(xiàn)遞歸(自己調(diào)自己)調(diào)用的任務(wù)
class MyTask extends RecursiveTask<Integer> { //拆分差值不能超過10,計算10以內(nèi)運算 private static final Integer VALUE = 10; private int begin ;//拆分開始值 private int end;//拆分結(jié)束值 private int result ; //返回結(jié)果 //創(chuàng)建有參數(shù)構(gòu)造 public MyTask(int begin,int end) { this.begin = begin; this.end = end; } //拆分和合并過程 @Override protected Integer compute() { //判斷相加兩個數(shù)值是否大于10 if((end-begin)<=VALUE) { //相加操作 for (int i = begin; i <=end; i++) { result = result+i; } } else {//進一步拆分 //獲取中間值 int middle = begin+(end- begin)/2; //拆分左邊 MyTask task01 = new MyTask(begin,middle); //拆分右邊 MyTask task02 = new MyTask(middle+1,end); //調(diào)用方法拆分 task01.fork(); task02.fork(); //合并結(jié)果 result = task01.join()+task02.join(); } return result; } } public class ForkJoinDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { //創(chuàng)建MyTask對象 MyTask myTask = new MyTask(0,100); //創(chuàng)建分支合并池對象 ForkJoinPool forkJoinPool = new ForkJoinPool(); ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask); //獲取最終合并之后結(jié)果 Integer result = forkJoinTask.get(); System.out.println(result); //關(guān)閉池對象 forkJoinPool.shutdown(); } }
package com.yxj.java8; import java.util.concurrent.RecursiveTask; public class ForkJoinCalculate extends RecursiveTask<Long>{ /** * */ private static final long serialVersionUID = 13475679780L; private long start; private long end; private static final long THRESHOLD = 10000L; //臨界值 public ForkJoinCalculate(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end - start; if(length <= THRESHOLD){ long sum = 0; for (long i = start; i <= end; i++) { sum += i; } return sum; }else{ long middle = (start + end) / 2; ForkJoinCalculate left = new ForkJoinCalculate(start, middle); left.fork(); //拆分,并將該子任務(wù)壓入線程隊列 ForkJoinCalculate right = new ForkJoinCalculate(middle+1, end); right.fork(); return left.join() + right.join(); } } }
package com.yxj.java8; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.stream.LongStream; import org.junit.Test; public class TestForkJoin { @Test public void test1(){ long start = System.currentTimeMillis(); ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinCalculate(0L, 10000000000L); long sum = pool.invoke(task); System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗費的時間為: " + (end - start)); //112-1953-1988-2654-2647-20663-113808 } @Test public void test2(){ long start = System.currentTimeMillis(); long sum = 0L; for (long i = 0L; i <= 10000000000L; i++) { sum += i; } System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗費的時間為: " + (end - start)); //34-3174-3132-4227-4223-31583 } @Test public void test3(){ long start = System.currentTimeMillis(); Long sum = LongStream.rangeClosed(0L, 10000000000L) .parallel() .sum(); System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗費的時間為: " + (end - start)); //2061-2053-2086-18926 } }
到此這篇關(guān)于Java中的Fork/Join框架使用詳解的文章就介紹到這了,更多相關(guān)Fork/Join框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
win10和win7下java開發(fā)環(huán)境配置教程
這篇文章主要為大家詳細(xì)介紹了win7下Java開發(fā)環(huán)境配置教程,win10下Java開發(fā)環(huán)境配置,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06Java 通過JDBC連接Mysql數(shù)據(jù)庫
本文給大家詳細(xì)介紹了java如何使用JDBC連接Mysql的方法以及驅(qū)動包的安裝,最后給大家附上了java通過JDBC連接其他各種數(shù)據(jù)庫的方法,有需要的小伙伴可以參考下。2015-11-11Java設(shè)計模式之命令模式CommandPattern詳解
這篇文章主要介紹了Java設(shè)計模式之命令模式CommandPattern詳解,命令模式是把一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤銷的操作,需要的朋友可以參考下2023-10-10Java中final,finally,finalize?有什么區(qū)別
這篇文章主要給大家分享的是?Java中final,finally,finalize?到底有什么區(qū)別,文章圍繞final,finally,finalize的相關(guān)資料展開詳細(xì)內(nèi)容,具有一定的參考的價值,需要的朋友可以參考一下2021-11-11Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例
本文主要介紹了Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05