Java Fork / Join進行并行編程

最近幾年,計算機處理器領域發生了范式轉變。 多年來,處理器制造商一直在提高時鐘頻率,因此開發人員享受到這樣的事實,即他們的單線程軟件執行得更快,而無需他們付出任何努力。 現在,處理器制造商青睞多核芯片設計,并且必須以多線程或多進程的方式編寫軟件才能充分利用硬件。 因此,軟件開發人員追趕的唯一方法是編寫利用并行性的應用程序,即使用多個CPU內核來處理所有任務,而不是使用單個更快的內核。 摩爾定律仍然適用,但適用范圍有所不同。

并行計算或并行化是一種計算形式,其中許多計算同時進行,其原理是大問題通常可以分為較小的問題,然后并行解決(“并行”)。 從本質上講,如果可以將CPU密集型問題劃分為較小的獨立任務,則可以將這些任務分配給不同的處理器。

關于多線程和并發,Java非常有趣。 它從一開始就支持Thread,而在過去,您可以使用帶有interrupt , join , sleep方法的低級方法來操縱線程的執行。 此外,所有對象繼承的notify和wait方法也可能會有所幫助。

可以通過這種方式控制應用程序的執行,但是過程有些繁瑣。 然后是Java 1.5中的并發包 ,它提供了一個更高級別的框架,開發人員可以使用該框架以更簡單,更容易和更不易出錯的方式處理線程。 該程序包提供了一堆在并發編程中通常有用的實用程序類。

多年以來,對“啟用并發”程序的需求變得越來越大,因此該平臺采取了這一步驟,進一步引入了Java SE 7的新并發功能 。 功能之一是引入了Fork / Join框架,該框架原本打算包含在JDK 1.5版本中,但最終沒有成功。

Fork / Join框架旨在使分而治之算法易于并行化。 這種類型的算法非常適合可以分為兩個或多個相同類型的子問題的問題。 他們使用遞歸將問題分解為簡單的任務,直到這些任務變得足夠簡單以至于可以直接解決。 然后將子問題的解決方案合并以給出原始問題的解決方案。 關于Fork / Join方法的出色介紹是文章“ Java SE中的Fork-Join開發 ”。

您可能已經注意到,Fork / Join方法類似于MapReduce ,因為它們都是并行化任務的算法。 但是,一個區別是,只有在必要時(如果太大),Fork / Join任務才將自己細分為較小的任務,而MapReduce算法將其作為工作的第一步將所有工作分為幾部分。

Fork / Join Java框架起源于JSR-166,您可以在Doug Lea領導的并發JSR-166興趣站點中找到更多信息。 實際上,如果您希望使用該框架并且沒有JDK 7,則必須在這里進行操作。如站點中所述,我們可以使用JDK 1.5和1.6中的相關類,而不必安裝最新的JDK。 為此,我們必須下載jsr166 jar并使用-Xbootclasspath / p:jsr166.jar選項啟動JVM。 請注意,您可能需要在“ jsr166.jar”之前加上其完整文件路徑。 之所以必須這樣做,是因為JAR包含一些重寫核心Java類的類(例如java.util包下的類)。 不要忘記為JSR-166 API文檔添加書簽。

因此,讓我們看看如何使用該框架解決一個實際問題。 我們將創建一個程序來計算斐波納契數 (一個經典的教學問題),并查看如何使用新類使我們盡可能快。 Java Fork / Join + Groovy文章中也解決了此問題。

首先,我們創建一個表示問題的類,如下所示:

package com.javacodegeeks.concurrency.forkjoin;public class FibonacciProblem {public int n;public FibonacciProblem(int n) {this.n = n;}public long solve() {return fibonacci(n);}private long fibonacci(int n) {System.out.println("Thread: " +Thread.currentThread().getName() + " calculates " + n);if (n <= 1)return n;else return fibonacci(n-1) + fibonacci(n-2);}}

如您所見,我們使用該解決方案的遞歸版本,這是一個典型的實現。 (請注意,此實現效率很高,因為它會一遍又一遍地計算相同的值。在實際情況下,已經緩存的計算值應在以后的執行中進行緩存和檢索)。 現在讓我們看一下單線程方法的外觀:

package com.javacodegeeks.concurrency.forkjoin;import org.perf4j.StopWatch;public class SillyWorker {public static void main(String[] args) throws Exception {int n = 10;StopWatch stopWatch = new StopWatch();FibonacciProblem bigProblem = new FibonacciProblem(n); long result = bigProblem.solve();   stopWatch.stop();System.out.println("Computing Fib number: " + n);System.out.println("Computed Result: " + result);System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());}}

我們只是創建一個新的FibonacciProblem并執行其solve方法,該方法將遞歸調用fibonacci方法。 我還使用漂亮的Perf4J庫來跟蹤經過的時間。 輸出將是這樣的(我隔離了最后幾行): …線程:main計算1線程:main計算0計算Fib數:10計算結果:55經過的時間:8如預期的那樣,所有工作都已完成只有一個線程(主線程)。 讓我們看看如何使用Fork / Join框架重寫它。 請注意,在Fibonacci解決方案中,將發生以下情況: fibonacci(n-1)+ fibonacci(n-2)因此,我們可以將這兩個任務中的每一個分配給一個新的工作程序(即新線程),然后工人已經完成處決,我們將加入結果。 考慮到這一點,我們引入了FibonacciTask類,該類本質上是將較大的Fibonacci問題劃分為較小的問題的一種方法。

package com.javacodegeeks.concurrency.forkjoin;import java.util.concurrent.RecursiveTask;public class FibonacciTask extends RecursiveTask<Long> {private static final long serialVersionUID = 6136927121059165206L;private static final int THRESHOLD = 5;private FibonacciProblem problem;public long result;public FibonacciTask(FibonacciProblem problem) {this.problem = problem;}@Overridepublic Long compute() {if (problem.n < THRESHOLD) { // easy problem, don't bother with parallelismresult = problem.solve();}else {FibonacciTask worker1 = new FibonacciTask(new FibonacciProblem(problem.n-1));FibonacciTask worker2 = new FibonacciTask(new FibonacciProblem(problem.n-2));worker1.fork();result = worker2.compute() + worker1.join();}return result;}}

注意:如果您沒有使用JDK 7,而是手動包含了JSR-166庫,則必須覆蓋默認的Java核心類。 否則,您將遇到以下錯誤: java.lang.SecurityException:禁止的程序包名稱:java.util.concurrent為避免這種情況,請使用以下參數將JVM設置為覆蓋類: -Xbootclasspath / p:lib / jsr166.jar我使用了“ lib / jsr166.jar”值,因為該JAR駐留在我的Eclipse項目中一個名為“ lib”的文件夾中。 配置如下所示:

我們的任務擴展了RecursiveTask類,該類是遞歸結果的ForkJoinTask 。 我們將覆蓋處理此任務執行的主要計算的計算方法。 在該方法中,我們首先檢查是否必須使用并行性(通過與閾值進行比較)。 如果這是一個易于執行的任務,我們將直接調用solve方法,否則我們將創建兩個較小的任務,然后分別執行每個任務。 執行發生在不同的線程中,然后將其結果合并。 這可以通過使用fork和join方法來實現。 讓我們測試一下實現:

package com.javacodegeeks.concurrency.forkjoin;import java.util.concurrent.ForkJoinPool;import org.perf4j.StopWatch;public class ForkJoinWorker {public static void main(String[] args) {// Check the number of available processorsint processors = Runtime.getRuntime().availableProcessors();System.out.println("No of processors: " + processors);int n = 10;StopWatch stopWatch = new StopWatch();   FibonacciProblem bigProblem = new FibonacciProblem(n);FibonacciTask task = new FibonacciTask(bigProblem);ForkJoinPool pool = new ForkJoinPool(processors);pool.invoke(task);long result = task.result;System.out.println("Computed Result: " + result);stopWatch.stop();System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());}}

我們首先檢查系統中可用的處理器數量,然后創建具有相應并行度的新ForkJoinPool 。 我們使用invoke方法分配并執行任務。 這是輸出(我已經隔離了第一個和最后一個方法): 處理器數量:8線程:ForkJoinPool-1-worker-7計算4線程:ForkJoinPool-1-worker-6計算4線程:ForkJoinPool-1-worker- 4計算4…線程:ForkJoinPool-1-worker-2計算1線程:ForkJoinPool-1-worker-2計算0計算結果:55經過的時間:16請注意,現在將計算委托給多個工作線程,每個工作線程其中的一項任務比原來的任務要小。 您可能已經注意到,經過的時間大于上一個。 之所以發生這種矛盾,是因為我們使用了較低的閾值(5)和較低的n值(10)。 由于創建了大量線程,因此引入了不必要的延遲。 對于較大的閾值(大約20)和較高的n(40和更高),框架的真正力量將變得顯而易見。 我對n> 40的值進行了一些快速壓力測試,下面是帶有結果的圖表:

顯然,Fork / Join框架的伸縮性比單線程方法好得多,并且可以在更短的時間內執行計算。 (如果您希望自己進行一些壓力測試,請不要忘記刪除FibonacciProblem類中的System.out調用。)查看Windows 7計算機( i7- 720QM(具有4個內核和超線程 ),同時使用了每種方法。


單線程: 在執行過程中,CPU的總使用率仍然很低(從未超過16%)。 如您所見,當單線程應用程序難以執行所有計算時,CPU利用率不足。

多線程:

CPU利用率要好得多,所有處理器都有助于進行總計算。 在Java中介紹Fork / Join框架時,我們已經結束了。 請注意,這里我只是做些表面介紹,還存在許多其他功能,它們隨時可以幫助我們利用多核CPU。 一個新的時代正在出現,因此開發人員應該熟悉這些概念。 與往常一樣,您可以在這里找到為本文生成的源代碼。 別忘了分享!

相關文章 :
  • 正確記錄應用程序的10個技巧
  • 每個程序員都應該知道的事情
  • Java最佳實踐–多線程環境中的DateFormat
  • Java最佳實踐–隊列之戰和鏈接的ConcurrentHashMap
  • Java最佳實踐–高性能序列化
相關片段:
  • 更一般的等待/通知機制的CountDownLatch示例
  • 受限連接池的阻塞隊列示例
  • 任務運行器的重入鎖示例
  • 可重入ReadWriteLock值計算器示例

翻譯自: https://www.javacodegeeks.com/2011/02/java-forkjoin-parallel-programming.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374757.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374757.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374757.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

arm-elf-gcc交叉編譯器的使用教程

arm-elf-gcc交叉編譯器的使用教程 一開始需要安裝arm-elf-gcc&#xff0c;但是這是一個32位的程序&#xff0c;我是安裝了64位的系統&#xff0c;據說安裝ia32.libs依賴庫能運行這個&#xff0c;但是看到博客上面前人安裝完了系統圖標少了一半&#xff0c;然后就怕了。經過了翻…

力扣刪除排序數組中的重復項 II

給你一個有序數組 nums &#xff0c;請你 原地 刪除重復出現的元素&#xff0c;使每個元素 最多出現兩次 &#xff0c;返回刪除后數組的新長度。 不要使用額外的數組空間&#xff0c;你必須在 原地 修改輸入數組 并在使用 O(1) 額外空間的條件下完成。 思路&#xff1a; 雙指針…

2 android學習資料

http://blog.csdn.net/lmj623565791 http://blog.csdn.net/harvic880925/article/details/50995268轉載于:https://www.cnblogs.com/YyuTtian/p/5440930.html

建立自己的GWT Spring Maven原型

大家好&#xff0c; 在觀看Justin撰寫的有關Spring和GWT的非常有趣的文章時&#xff0c;我認為展示如何構建自己的自定義Maven原型非常有用。我們將展示的原型基于Justin的上一個項目&#xff0c;并包括各種技術&#xff0c;例如Spring &#xff0c; GWT &#xff0c; AspectJ…

C# 連接Oracle數據庫異常總結

這2天因為工作需要連接Oracle數據庫&#xff0c;中間發生了很多問題 一、使用OleDbConnection連接數據庫 ------------------ ProviderOraOLEDB.Oracle.1;User IDsajet;Passwordtech;Data Source(DESCRIPTION (ADDRESS_LIST (ADDRESS (PROTOCOL TCP)(HOST 192.168.66.225)(…

力扣顏色分類

給定一個包含紅色、白色和藍色&#xff0c;一共 n 個元素的數組&#xff0c;原地對它們進行排序&#xff0c;使得相同顏色的元素相鄰&#xff0c;并按照紅色、白色、藍色順序排列。 此題中&#xff0c;我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。 思路:將紅色和藍色…

Cassandra,MongoDB,CouchDB,Redis,Riak,HBase比較

克里斯托夫科瓦奇&#xff08;KristfKovcs&#xff09;對六個最受歡迎的“ NoSQL ”數據庫實現進行了非常有趣的簡短比較 。 除了Kristf的工作之外&#xff0c;我還想提供一些鏈接&#xff0c;我相信這些鏈接將對有興趣關注“ NoSQL ”社區的所有人員提供幫助&#xff1a; No…

程序員需要謹記的九大安全編碼規則

歷史已經證明&#xff0c;軟件設計的缺陷一直是導致其漏洞被利用的最主要的罪魁禍首。安全專家發現&#xff0c;多數漏洞源自常見軟件中相對有限的一些漏洞。軟件開發者和設計者應當嚴格檢查程序中的各種錯誤&#xff0c;盡量在軟件部署之前就減少或清除其中的漏洞。 下面列舉的…

HDU 2897

Problem Description當日遇到月&#xff0c;于是有了明。當我遇到了你&#xff0c;便成了侶。那天&#xff0c;日月相會&#xff0c;我見到了你。而且&#xff0c;大地失去了光輝&#xff0c;你我是否成侶&#xff1f;這注定是個凄美的故事。&#xff08;以上是廢話&#xff09…

力扣合并兩個有序數組

題目&#xff1a;給你兩個按 非遞減順序 排列的整數數組 nums1 和 nums2&#xff0c;另有兩個整數 m 和 n &#xff0c;分別表示 nums1 和 nums2 中的元素數目。 請你 合并 nums2 到 nums1 中&#xff0c;使合并后的數組同樣按 非遞減順序 排列。 注意&#xff1a;最終&#…

Google Guava庫必需品

我希望代碼簡單&#xff0c;短而又易于閱讀。 不必要的復雜性分散了人們對真實情況的理解&#xff0c;使他們難以理解&#xff0c;并且可能成為生產力的真正殺手。 您知道&#xff0c;纏結的for循環和索引可以跟蹤是否/其他情況和切換用例&#xff0c;空/驗證檢查&#xff0c;轉…

單調棧3_水到極致的題 HDOJ4252

A Famous City 題目大意 給出正視圖 每一列為樓的高度 最少有幾座樓 坑點 樓高度可以為0 代表沒有樓 貢獻了兩發RE 原因 if(!s.empty()&&tem){s.push(tem); continue;}并不能篩去 空棧且 tem為0的情況 改為 if(!s.empty()){if(tem) s.push(tem); continue;} 后AC 題目…

eclipse配置遠程調試

一、配置 1、cd apache-tomcat/bin 2、vi startup.sh文件 3、在文件開頭處&#xff0c;添加下方代碼(address代表的是調試端口) declare -x CATALINA_OPTS"-Xdebug -Xnoagent -Djava.compilerNONE -Xrunjdwp:servery,transportdt_socket,suspendn,address…

力扣兩數之和 II - 輸入有序數組

題目:給定一個已按照 非遞減順序排列 的整數數組 numbers &#xff0c;請你從數組中找出兩個數滿足相加之和等于目標數 target 。 我的代碼&#xff1a; 對撞指針 class Solution {public int[] twoSum(int[] numbers, int target) {int low 0;//指向頭int high numbers.le…

SpringMVC 3 Tiles 2.2.2集成教程

Apache Tiles是基于Java的Web應用程序的流行且最常用的模板框架。 由于Struts 1.x使用Tiles作為其默認模板框架&#xff0c;因此Tiles變得更加流行。 SpringMVC是一個MVC框架&#xff0c;例如Struts &#xff0c;也支持將Tiles集成為其模板框架。 讓我們看看如何集成SpringMVC和…

[團隊項目3.0]Scrum團隊成立

Scrum團隊成立 5.Scrum團隊成立 5.1 團隊名稱&#xff0c;團隊目標、團隊口號、團隊照&#xff1b; 5.2 角色分配 產品負責人: 決定開發內容和優先級排序&#xff0c;最大化產品以及開發團隊工作的價值。 Scrum Master&#xff1a; 負責確保團隊遵循 Scrum 的理論、實踐和規則。…

Base64編碼的java實現

Java本身是提供了Base64編碼的工具包的&#xff0c;做項目的時候自己實現了個&#xff0c;在這里記錄一下&#xff1a; 1 /** Base64編碼數組 */2 private static final String base64EncodeChars "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456…

Character.isLetterOrDigit(ch)判斷ch是否為字母或數字

Character.isLetter(ch) 判斷ch是否為字母 Character.isDigit(ch) 判斷ch是否為數字 Character.isLetterOrDigit(ch) 判斷ch是否為字母或數字 /* 例子*/char ch q;System.out.println(Character.isLetter(ch));System.out.println(Character.isDigit(ch));System.out.print…

高級SmartGWT教程,第1部分

賈斯汀&#xff08;Justin&#xff09;&#xff0c;帕特&#xff08;Pat&#xff09;和我已經開始著手一個需要用戶界面進行管理和管理的副項目。 在與SmartGWT和GWT共同工作了一段時間之后&#xff0c;我們決定使用SmartGWT創建接口。 我們非常喜歡視覺組件&#xff08;請查看…

git 技巧

將某個文件回退到某個版本 git co d359624286d9c1f022b8b3b6f2d3fe3b6524188b build.sh 查看某個文件在某個版本時的內容 git show d359624286d9c1f022b8b3b6f2d3fe3b6524188b:build.sh 如果想把這個文件重命名保存 git show d359624286d9c1f022b8b3b6f2d3fe3b6524188b:build.s…