做網站為什么圖片上傳不了整站優(yōu)化系統(tǒng)
線程數(shù)超過CPU核心數(shù)是沒有任何意義的【因為要使用CPU密集型運算】
Fork/Join:線程池的實現(xiàn),體現(xiàn)是分治思想,適用于能夠進行任務拆分的 CPU 密集型運算,用于并行計算
任務拆分:將一個大任務拆分為算法上相同的小任務,直至不能拆分可以直接求解。跟遞歸相關的一些計算,如歸并排序、斐波那契數(shù)列都可以用分治思想進行求解
-
Fork/Join 在分治的基礎上加入了多線程,把每個任務的分解和合并交給不同的線程來完成,提升了運算效率
-
ForkJoin 使用 ForkJoinPool 來啟動,是一個特殊的線程池,默認會創(chuàng)建與 CPU 核心數(shù)大小相同的線程池
-
任務有返回值繼承 RecursiveTask,沒有返回值繼承 RecursiveAction【特殊:不能用Runnable或者Callable了】
?
public static void main(String[] args) {ForkJoinPool pool = new ForkJoinPool(4);System.out.println(pool.invoke(new MyTask(5)));//拆分 5 + MyTask(4) --> 4 + MyTask(3) -->}?// 1~ n 之間整數(shù)的和class MyTask extends RecursiveTask<Integer> {private int n;?public MyTask(int n) {this.n = n;}?@Overridepublic String toString() {return "MyTask{" + "n=" + n + '}';}?@Overrideprotected Integer compute() {// 如果 n 已經為 1,可以求得結果了if (n == 1) {return n;}// 將任務進行拆分(fork)MyTask t1 = new MyTask(n - 1);t1.fork(); //執(zhí)行計算// 合并(join)結果int result = n + t1.join(); //獲取上面fork的執(zhí)行結果return result;}}
繼續(xù)拆分優(yōu)化:二分法
class AddTask extends RecursiveTask<Integer> {int begin;int end;public AddTask(int begin, int end) {this.begin = begin;this.end = end;}@Overridepublic String toString() {return "{" + begin + "," + end + '}';}@Overrideprotected Integer compute() {// 5, 5if (begin == end) {return begin;}// 4, 5 防止多余的拆分 提高效率if (end - begin == 1) {return end + begin;}// 1 5int mid = (end + begin) / 2; // 3AddTask t1 = new AddTask(begin, mid); // 1,3t1.fork();AddTask t2 = new AddTask(mid + 1, end); // 4,5t2.fork();int result = t1.join() + t2.join();return result;}}
ForkJoinPool 實現(xiàn)了工作竊取算法來提高 CPU 的利用率:
-
每個線程都維護了一個雙端隊列,用來存儲需要執(zhí)行的任務
-
工作竊取算法允許空閑的線程從其它線程的雙端隊列中竊取一個任務來執(zhí)行
-
竊取的必須是最晚的任務,避免和隊列所屬線程發(fā)生競爭,但是隊列中只有一個任務時還是會發(fā)生競爭
難在如何拆分,后面JDK8就封裝到stream的api了,并行流