線程池架構Fork-Join 框架
就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 彙總。
工作竊取 模式(work-stealing)
當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加到線程隊列中,當該線程隊列沒有需要執行的任務時,再從一個隨機線程的隊列中偷一個並把它放在自己的隊列中。
相對於一般的線程池實現,fork-join框架的優勢體現在對其中包含的任務的處理方式上.在一般的線程池中,如果一個線程正在執行的任務由於某些原因無法繼續運行,那麼該線程會處於等待狀態。而在fork-join框架實現中,如果某個子問題由於等待另外一個子問題的完成而無法繼續運行。那麼處理該子問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式減少了線程的等待時間,提高了性能。
代碼演示
package com.xiaoqiang;
import java.time.Duration;
import java.time.Instant;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
* 本案例適用於大量操作
* 若少量數據可直接操作
* 程序執行速度受臨界值較大
* 請選擇合理的臨界值
* @author xiaoqiang
* @time 2017-7-5
*/
public class ForkJoin extends RecursiveTask<Long> {
private static final long serialVersionUID = 7633953255462137626L;
private long start;// 開始值
private long end;// 結束值
private static final long THURSHOLD = Math.abs(new Random().nextInt());// 臨界值
public ForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
/**
* 結束值與開始至之差小於臨界值時 程序繼續把大任務劃分爲小任務
*/
@Override
protected Long compute() {
long temp = end - start;
if (temp <= THURSHOLD) {
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2;
// 遞歸調用
ForkJoin left = new ForkJoin(start, middle);
ForkJoin right = new ForkJoin(++middle, end);
left.fork(); // 進行拆分 繼續執行判斷
right.fork();
return left.join() + right.join();// 合併結果集
}
}
public static void main(String[] args) {
Instant time1 = Instant.now();//JAVA8新類 可以使用System.currentTimeMillis() 替代
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoin(0L, 50000000000L);
long sum = pool.invoke(task);
Instant time2 = Instant.now();
System.out.println("分割後耗費時間:" + Duration.between(time1, time2).toMillis() + "毫秒");
sum = 0L;
Instant time3 = Instant.now();
for (long i = 0L; i <= 50000000000L; i++) {
sum += i;
}
Instant time4 = Instant.now();
System.out.println("未分割耗費時間:" + Duration.between(time3, time4).toMillis() + "毫秒");
// 分割後耗費時間:8284毫秒
// 未分割耗費時間:15552毫秒
// 若數據較少 則分割會額外耗費時間
}
}