分叉并加入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.mzph.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…