分叉并加入Java 7 – JSR 166并發實用程序

Java 7最有趣的改進之一是對并發的更好支持。 使用JSR 166并發實用程序,我們可以對并發進行一些非常有用的改進。 在我看來,fork-join庫在軟件工程中具有很高的實際應用潛力。 Fork and join為算法提供了非常簡單的編程模型,可以將其實現為遞歸任務。 有很多算法可以使用分治法來實現。

在未來幾年中,我們將看到標準臺式機,筆記本電腦和服務器計算機中內核的數量不斷增加。 原因很簡單:添加額外的內核比構建更快的單個處理器便宜。 因此,我們將不得不編寫更多支持并發的軟件以利用更好的硬件。

老實說,我不喜歡并發。 我的個人規則是“您需要一個充分的理由來實現并發,并且如果需要做的話必須非常小心。”在過去的幾年中,我看到的錯誤實現多于工作。 這就是為什么我喜歡fork&join庫的原因。 清晰的編程模型可實現樣板代碼,可防止您出錯。 但是,如果您打算使用fork和join,請花一些時間來了解其行為。

文件#1和#2中的示例與Java 7文檔中的示例代碼非常相似。 通常,使用遞歸算法的斐波那契數不是一個好主意,因為存在更好的線性解決方案(請比較http://nayuki.eigenstate.org/page/fast-fibonacci-algorithms ),但它更易于實現和理解相對于其它的。 因此,讓我們看一下示例:

// File #1: FibonacciTask.java  [error handling, parameter validation and asserts removed] package com.sprunck.sample;import java.util.concurrent.RecursiveTask;public class FibonacciTask extends RecursiveTask<Long> {private static final long serialVersionUID = 1L;private final long inputValue;public FibonacciTask(long inputValue) {this.inputValue = inputValue;}@Overridepublic Long compute() {if (inputValue == 0L) {return 0L;} else if (inputValue <= 2L) {return 1L;} else {final FibonacciTask firstWorker = new FibonacciTask(inputValue - 1L);firstWorker.fork();final FibonacciTask secondWorker = new FibonacciTask(inputValue - 2L);return secondWorker.compute() + firstWorker.join();}}
}
// File #2: FibonacciTaskTest.java package com.sprunck.sample;import java.util.concurrent.ForkJoinPool;
import junit.framework.Assert;
import org.junit.Test;public class FibonacciTaskTest {// it makes no sense to create more threads than available cores (no speed improvement here)private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();// create thread poolprivate final ForkJoinPool pool = new ForkJoinPool(AVAILABLE_PROCESSORS);@Testpublic void testFibonacciArray() {// more test data: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.htmllong results[] = { 0L, 1L, 1L, 2L, 3L, 5L, 8L, 13L, 21L, 34L, 55L, 89L, 144L, 233L, 377L, 610L, 987L, 1597L,2584L, 4181L, 6765L };for (int inputValue = 0; inputValue < results.length; inputValue++) {final FibonacciTask task = new FibonacciTask(inputValue);System.out.print("Fibonacci(" + inputValue + ") = ");final long result = pool.invoke(task);System.out.println(result);Assert.assertEquals(results[inputValue], result);}}
}

// FibonacciTaskTest.java的輸出

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1
Fibonacci(3) = 2
Fibonacci(4) = 3
Fibonacci(5) = 5
Fibonacci(6) = 8
Fibonacci(7) = 13
Fibonacci(8) = 21
Fibonacci(9) = 34
Fibonacci(10) = 55
Fibonacci(11) = 89
Fibonacci(12) = 144
Fibonacci(13) = 233
Fibonacci(14) = 377
Fibonacci(15) = 610
Fibonacci(16) = 987
Fibonacci(17) = 1597
Fibonacci(18) = 2584
Fibonacci(19) = 4181
Fibonacci(20) = 6765

到目前為止,這是一個簡單明了的解決方案。 沒有用于并行的樣板代碼,例如線程同步。

但我想鼓勵您更深入地了解解決方案中發生的情況。 在文件#3和#4中,您可以找到同一程序的增強版本。 第一個版本和第二個版本之間的唯一區別是,一些代碼可以跟蹤執行期間發生的事情,而較小的slowTask()可以模擬更實際的行為。

// File #3: FibonacciTaskTraces.java package com.sprunck.sample;import java.util.concurrent.RecursiveTask;public class FibonacciTaskTraces extends RecursiveTask<Long> {private static final long serialVersionUID = 1L;// just needed to format debug outputpublic static final String OUTPUT_PREFIX = " | ";private final String prefix;private final long inputValue;public FibonacciTaskTraces(long inputValue, final String prefix) {this.inputValue = inputValue;this.prefix = prefix;}@Overridepublic Long compute() {if (inputValue == 0L) {slowTask();return 0L;} else if (inputValue <= 2L) {slowTask();return 1L;} else {final long firstValue = inputValue - 1L;System.out.println(prefix + " - Fibonacci(" + firstValue + ") <- " + Thread.currentThread().getName()+ " (fork) ");final FibonacciTaskTraces firstWorker = new FibonacciTaskTraces(firstValue, prefix + OUTPUT_PREFIX);firstWorker.fork();final long secondValue = inputValue - 2L;System.out.println(prefix + " - Fibonacci(" + secondValue + ") <- " + Thread.currentThread().getName());final FibonacciTaskTraces secondWorker = new FibonacciTaskTraces(secondValue, prefix + OUTPUT_PREFIX);long result = secondWorker.compute() + firstWorker.join();System.out.println(prefix + " - Fibonacci(" + inputValue + ") = " + result + " <- "+ Thread.currentThread().getName() + " (join)");slowTask();return result;}}/** just simulate a longer running task (with out disturbing the other threads) */private void slowTask() {for (int k = 0, i = 0; i < 1000 * 1000 * 100; i++) {i = i + k;}}
}
// File #4: FibonacciTaskTracesTask.javapackage com.sprunck.sample;import java.util.concurrent.ForkJoinPool;
import junit.framework.Assert;
import org.junit.Test;public class  FibonacciTaskTracesTest {// it makes no sense to create more threads than available cores (no speed improvement here)private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();// create thread poolprivate final ForkJoinPool pool = new ForkJoinPool(AVAILABLE_PROCESSORS);@Testpublic void testFibonacciArrayTraces() {// more test data: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.htmllong results[] = { 0L, 1L, 1L, 2L, 3L, 5L, 8L, 13L };for (int inputValue = 0; inputValue < results.length; inputValue++) {final FibonacciTaskTraces task = new FibonacciTaskTraces(inputValue, " | ");System.out.println("invoke Fibonacci(" + inputValue + ")  <- " + Thread.currentThread().getName());final long result = pool.invoke(task);System.out.println("result = " + result + "\n");Assert.assertEquals(results[inputValue], result);}}
}

// FibonacciTaskTracesTest.java的輸出

invoke Fibonacci(0)  <- mainresult = 0invoke Fibonacci(1)  <- mainresult = 1invoke Fibonacci(2)  <- mainresult = 1invoke Fibonacci(3)  <- main|  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)result = 2invoke Fibonacci(4)  <- main|  - Fibonacci(3) <- ForkJoinPool-1-worker-1 (fork) |  - Fibonacci(2) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-1 (join)result = 3invoke Fibonacci(5)  <- main|  - Fibonacci(4) <- ForkJoinPool-1-worker-1 (fork) |  - Fibonacci(3) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2 (fork) |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2|  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)|  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-2 (join)|  - Fibonacci(5) = 5 <- ForkJoinPool-1-worker-1 (join)result = 5invoke Fibonacci(6)  <- main|  - Fibonacci(5) <- ForkJoinPool-1-worker-1 (fork) |  - Fibonacci(4) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(3) <- ForkJoinPool-1-worker-1 (fork) |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(4) <- ForkJoinPool-1-worker-2 (fork) |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2|  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)|  |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2 (fork) |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2|  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-1 (join)|  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  |  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-2 (join)|  |  - Fibonacci(5) = 5 <- ForkJoinPool-1-worker-2 (join)|  - Fibonacci(6) = 8 <- ForkJoinPool-1-worker-1 (join)result = 8invoke Fibonacci(7)  <- main|  - Fibonacci(6) <- ForkJoinPool-1-worker-1 (fork) |  - Fibonacci(5) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(4) <- ForkJoinPool-1-worker-1 (fork) |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-1|  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  |  - Fibonacci(5) <- ForkJoinPool-1-worker-2 (fork) |  |  - Fibonacci(4) <- ForkJoinPool-1-worker-2|  |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2 (fork) |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2|  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)|  |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-1 (fork) |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1|  |  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  |  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-2 (join)|  |  |  - Fibonacci(4) <- ForkJoinPool-1-worker-2 (fork) |  |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2|  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2 (fork) |  |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-2|  |  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)|  |  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-1 (join)|  |  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-2 (join)|  |  - Fibonacci(5) = 5 <- ForkJoinPool-1-worker-1 (join)|  |  |  |  - Fibonacci(3) <- ForkJoinPool-1-worker-2 (fork) |  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-2|  |  |  |  |  - Fibonacci(2) <- ForkJoinPool-1-worker-1 (fork) |  |  |  |  |  - Fibonacci(1) <- ForkJoinPool-1-worker-1|  |  |  |  |  - Fibonacci(3) = 2 <- ForkJoinPool-1-worker-1 (join)|  |  |  |  - Fibonacci(4) = 3 <- ForkJoinPool-1-worker-2 (join)|  |  |  - Fibonacci(5) = 5 <- ForkJoinPool-1-worker-2 (join)|  |  - Fibonacci(6) = 8 <- ForkJoinPool-1-worker-2 (join)|  - Fibonacci(7) = 13 <- ForkJoinPool-1-worker-1 (join)result = 13

現在,輸出使您可以更深入地了解程序的處理。 出現以下斐波納契數計算方法:

  • 前三個斐波那契數在主線程中處理,
  • 下一個斐波那契數僅在一個新線程(ForkJoinPool-1-worker-1)中處理,并且
  • 從第五個斐波納契數開始,使用了兩個線程(ForkJoinPool-1-worker-1和ForkJoinPool-1-worker-2)。

該算法效率低下,因為在處理過程中有很多冗余操作(重新計算相同的斐波那契數)。 在現實生活中的應用程序中,您應該小心使用這種效率低下的算法。 一些痕跡有助于理解會發生什么。

推薦品

  1. 使用fork和join既簡單又直接,但是要花一些時間來跟蹤和理解您的實現。
  2. 有時實現同一算法的兩個版本(一個用于分析,另一個用于生產)會有所幫助。
  3. 花一些時間來設計和理解更好的并發算法是一項不錯的投資。

以此方式開發了概率計算器 ( 概率計算器演示– PCALC )。

參考: 如何在Java 7 – JSR 166并發實用程序中實現fork and join? 由我們的JCG合作伙伴 Markus Sprunck在Software Engineering Candies博客上獲得。


翻譯自: https://www.javacodegeeks.com/2012/04/fork-and-join-in-java-7-jsr-166.html

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

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

相關文章

linux內核源碼代碼量,Linux內核源代碼數量已經超過1000萬行

Linux版本2.6.27更新后,人們發現,這一內核的源代碼數量已經超過了1000萬行.當然,這些行數僅僅是計算機統計出來的行數,包括空白行,為了代碼的可讀性增加的注釋等,當然Linux和所有的長期項目一樣,隨著時間的推移,舊的代碼 會被丟棄和更換,但總體規模來說,Linux的內核在不斷增強,…

Python之路【第八篇】:堡壘機實例以及數據庫操作

Python之路【第八篇】&#xff1a;堡壘機實例以及數據庫操作 堡壘機前戲 開發堡壘機之前&#xff0c;先來學習Python的paramiko模塊&#xff0c;該模塊機遇SSH用于連接遠程服務器并執行相關操作 SSHClient 用于連接遠程服務器并執行基本命令 基于用戶名密碼連接&#xff1a; 12…

關于typedef的使用方法

在計算機編程語言中用來為復雜的聲明定義簡單的別名。與宏定義有些差異。它本身是一種存儲類的keyword&#xff0c;與auto、extern、mutable、static、register等keyword不能出如今同一個表達式中。typedef聲明&#xff0c;簡稱typedef&#xff0c;為現有類型創建一個新的名字&…

ADF BC:創建綁定到業務組件的UI表

在此示例中&#xff0c;我們將展示如何創建綁定到業務組件的簡單UI表&#xff08;af&#xff1a;table&#xff09;。 我再次嘗試使用簡單的標準在網上進行搜索&#xff1a; “如何創建綁定到業務組件ADF 11g的af&#xff1a;table” 我必須承認我沒有得到我想要的答案。 信息…

linux驅動程序混合架構,嵌入式系統最小驅動框架(類似linux驅動程序架構)(示例代碼)...

2010年就打算把linux里的驅動框架核心代碼摳出來的&#xff0c;但是由于懶而且linux代碼量大&#xff0c;一直下不了手。最近調試的intel curie里驅動架構也類似linux&#xff0c;代碼就少多了&#xff0c;由于工作需要不得不梳理一下這一堆代碼&#xff0c;今天花了一下午&…

MyBaits 錯誤分析

錯誤原因&#xff1a;在DAO的映射文件中&#xff0c;在映射標簽中的type類型寫成DAO類了&#xff0c;應該寫成javaBean轉載于:https://www.cnblogs.com/shuaiandjun/p/5428847.html

超越JUnit –測試框架的替代方案

JUnit是事實上的Java單元測試框架&#xff0c;但是可能有一些新的&#xff08;不是那么新的&#xff09;框架可以用于Web開發。 在采用之前可能要問自己的問題&#xff1a; 它們是否快速&#xff0c;容易開發&#xff0c;因此成本低廉&#xff1f; 他們運行快并因此鼓勵采用嗎…

tensorflow mnist read_data_sets fails

下載處理mnist數據時出現如下錯誤 VisibleDeprecationWarning: converting an array with ndim > 0 to an index will result in an error in the future 解決方法&#xff1a; 在input_data.py文件中return numpy.frombuffer(bytestream.read(4), dtypedt) 后添加[0] retur…

斑馬打印機linux驅動安裝教程,linux-Zebra軟件包的基本安裝與配置

Zebra是一個路由軟件包&#xff0c;提供基于TCP/IP路由服務&#xff0c;支持RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, BGP- 4,和 BGP-4等眾多路由協議。Zebra還支持BGP特性路由反射器(Route Reflector)。除了傳統的 IPv4路由協議&#xff0c;Zebra也支持IPv6路由協議。如果運行的…

iOS 改變App狀態欄顏色為白色

默認狀態欄為黑色&#xff0c;對于某些App不是很美觀&#xff0c;變成白色很簡單&#xff0c;只需要兩個步驟。 1.在Info.plist中添加新項目&#xff0c;View controller-based status bar appearance&#xff0c;Boolean值為No. 2.在AppDelegate的- (BOOL)application:(UIAppl…

Java 7對抑制異常的支持

在JDK 7中 &#xff0c;向Throwable類&#xff08; Exception和Error類的父類&#xff09;添加了一個新的構造函數和兩個新方法。 添加了新的構造函數和兩個新方法以支持“抑制的異常”&#xff08;不要與吞咽或忽略異常的不良做法相混淆&#xff09;。 在本文中&#xff0c;我…

linux 如何做共享磁盤陣列,在Linux上玩轉磁盤陣列分享

大部分用戶都會擔心&#xff0c;萬一硬盤發生故障&#xff0c;一、使用磁盤陣列可以帶來哪些好處?在具體如何配置磁盤陣列之前&#xff0c;筆者要先給大家介紹一下利用磁盤陣列的好處。先給大家一點動力&#xff0c;讓大家能夠繼續看下面的內容。第一個好處是磁盤陣列可以提高…

my-innodb-heavy-4g.cnf

my-innodb-heavy-4g.cnf轉載于:https://www.cnblogs.com/xiluhua/p/6231834.html

易于使用的單位和集成代碼

此示例說明如何使用Maven和Sonar生成單元測試和集成測試的覆蓋率。 它使用非常簡單的技術&#xff0c;只需10-15分鐘即可在任何現有的Maven構建中運行。 它可用于單元&#xff0c;集成&#xff0c;ATDD或任何其他類型的測試套件。 覆蓋率結果顯示在Sonar中。 有什么事嗎&#x…

Dij的堆優化

#include<algorithm> #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define M 100000 #define pa pair<int,int>//優先比較第一個元素 using namespace std; int d[M],n,m,cnt,head[M],next[M],u[M],dis[M],n…

linux db2sysc 內存,db2sysc進程占用linux內存持續增長,請各位指點。

該服務器近期做過的變更情況&#xff1a;變更前&#xff0c;使用 sar -r 1 3 看內存使用率服務器內存使用率一直是70%該服務器原為獨立物理服務器&#xff0c;經過虛擬化遷移到EXS上成為虛擬服務器。遷移后發現swap無法啟動。原因是原物理服務器硬盤控制器為cciss。/etc/fstab …

k8s的探針

一、探針原理 分布式系統和微服務體系結構的挑戰之一是自動檢測不正常的應用程序&#xff0c;并將請求&#xff08;request&#xff09;重新路由到其他可用系統&#xff0c;恢復損壞的組件。健康檢查是應對該挑戰的一種可靠方法。使用 Kubernetes&#xff0c;可以通過探針配置運…

第一百三十節,JavaScript,封裝庫--連綴

JavaScript&#xff0c;封裝庫--連綴 學習要點&#xff1a; 1.連綴介紹 2.改寫庫對象 本章我們重點來介紹&#xff0c;在調用庫的時候&#xff0c;我們需要能夠在前臺調用的時候可以同時設置多個操作&#xff0c;比如設置CSS&#xff0c;設置innerHTML&#xff0c;設置click事件…

Spring3:類型安全依賴項注入

在從Spring跳到類型安全依賴注入之前&#xff0c;我想討論一下我們之前所做的方式。 我們一直在借助Spring的Autowired注釋按類型使用依賴項注入。 像這樣的東西會注入Spring Bean。 Autowired private StudentDao studentDao; // Autowires by type. Injects the instance who…

userData IE

蠻討厭IE的&#xff0c;因為他常常需要特別照顧&#xff0c;就像DOM Storage(sessionStorage和localStorage)只能支持IE8&#xff0c;對于以下的只能使用userData。 原理&#xff1a;通過在document元素后面附加一個專屬的“DHTML行為”來實現客戶端存儲&#xff0c; var memor…