ork/join框架是ExecutorService
接口的一种具体实现,目的是为了帮助你更好地利用多处理器带来的好处。它是为那些能够被递归地拆解成子任务的工作类型量身设计的。其目的在于能够使用所有可用的运算能力来提升你的应用的性能。
类似于ExecutorService
接口的其他实现,fork/join框架会将任务分发给线程池中的工作线程。fork/join框架的独特之处在与它使用工作窃取(work-stealing)算法。完成自己的工作而处于空闲的工作线程能够从其他仍然处于忙碌(busy)状态的工作线程处窃取等待执行的任务。
fork/join框架的核心是ForkJoinPool
类,它是对AbstractExecutorService
类的扩展。ForkJoinPool
实现了工作偷取算法,并可以执行ForkJoinTask
任务。
基本使用方法
使用fork/join框架的第一步是编写执行一部分工作的代码。你的代码结构看起来应该与下面所示的伪代码类似:
5 |
分别触发(invoke)这两个子任务的执行,并等待结果
|
你需要将这段代码包裹在一个ForkJoinTask
的子类中。不过,通常情况下会使用一种更为具体的的类型,或者是RecursiveTask
(会返回一个结果),或者是RecursiveAction
。
当你的ForkJoinTask
子类准备好了,创建一个代表所有需要完成工作的对象,然后将其作为参数传递给一个ForkJoinPool
实例的invoke()
方法即可。
要清晰,先模糊
想要了解fork/join框架的基本工作原理,接下来的这个例子会有所帮助。假设你想要模糊一张图片。原始的source图片由一个整数的数组表示,每个整数表示一个像素点的颜色数值。与source图片相同,模糊之后的destination图片也由一个整数数组表示。
对图片的模糊操作是通过对source数组中的每一个像素点进行处理完成的。处理的过程是这样的:将每个像素点的色值取出,与周围像素的色值(红、黄、蓝三个组成部分)放在一起取平均值,得到的结果被放入destination数组。因为一张图片会由一个很大的数组来表示,这个流程会花费一段较长的时间。如果使用fork/join框架来实现这个模糊算法,你就能够借助多处理器系统的并行处理能力。下面是上述算法结合fork/join框架的一种简单实现:
01 |
public class ForkBlur extends RecursiveAction {
|
02 |
private int [] mSource;
|
05 |
private int [] mDestination;
|
08 |
private int mBlurWidth = 15 ;
|
10 |
public ForkBlur( int [] src, int start, int length, int [] dst) {
|
17 |
protected void computeDirectly() {
|
18 |
int sidePixels = (mBlurWidth - 1 ) / 2 ;
|
19 |
for ( int index = mStart; index < mStart + mLength; index++) {
|
21 |
float rt = 0 , gt = 0 , bt = 0 ;
|
22 |
for ( int mi = -sidePixels; mi <= sidePixels; mi++) {
|
23 |
int mindex = Math.min(Math.max(mi + index, 0 ),
|
25 |
int pixel = mSource[mindex];
|
26 |
rt += ( float )((pixel & 0x00ff0000 ) >> 16 )
|
28 |
gt += ( float )((pixel & 0x0000ff00 ) >> 8 )
|
30 |
bt += ( float )((pixel & 0x000000ff ) >> 0 )
|
35 |
int dpixel = ( 0xff000000 ) |
|
36 |
((( int )rt) << 16 ) |
|
37 |
((( int )gt) << 8 ) |
|
38 |
((( int )bt) << 0 );
|
39 |
mDestination[index] = dpixel;
|
接下来你需要实现父类中的compute()
方法,它会直接执行模糊处理,或者将当前的工作拆分成两个更小的任务。数组的长度可以作为一个简单的阀值来判断任务是应该直接完成还是应该被拆分。
01 |
protected static int sThreshold = 100000 ;
|
03 |
protected void compute() {
|
04 |
if (mLength < sThreshold) {
|
09 |
int split = mLength / 2 ;
|
11 |
invokeAll( new ForkBlur(mSource, mStart, split, mDestination),
|
12 |
new ForkBlur(mSource, mStart + split, mLength - split,
|
如果前面这个方法是在一个RecursiveAction
的子类中,那么设置任务在ForkJoinPool
中执行就再直观不过了。通常会包含以下一些步骤:
- 创建一个表示所有需要完成工作的任务。
3 |
ForkBlur fb = new ForkBlur(src, 0 , src.length, dst);
|
- 创建将要用来执行任务的
ForkJoinPool
。
1 |
ForkJoinPool pool = new ForkJoinPool();
|
- 执行任务。
想要浏览完成的源代码,请查看ForkBlur
,其中还包含一些创建destination图片文件的额外代码。
标准实现
除了能够使用fork/join框架来实现能够在多处理系统中被并行执行的定制化算法(如前文中的ForkBlur.java例子),在Java SE中一些比较常用的功能点也已经使用fork/join框架来实现了。在Java SE 8中,java.util.Arrays
类的一系列parallelSort()
方法就使用了fork/join来实现。这些方法与sort()
系列方法很类似,但是通过使用fork/join框架,借助了并发来完成相关工作。在多处理器系统中,对大数组的并行排序会比串行排序更快。这些方法究竟是如何运用fork/join框架并不在本教程的讨论范围内。想要了解更多的信息,请参见Java API文档。
其他采用了fork/join框架的方法还包括java.util.streams
包中的一些方法,此包是作为Java SE 8发行版中Project Lambda
的一部分。想要了解更多信息,请参见Lambda Expressions
一节。
(全文完)如果您喜欢此文请点赞,分享,评论。
分享到:
相关推荐
新特性主要涉及:对于JDK7中Fork/Join并行处理的升级;支持Lambda表达式;添加了Stream API;对于注解的拓展,加入了类型注解、重复注解;在G1回收器中支持字符串去重;内存空间中删除了永久代,引入了元空间。
8. **并行和并发改进**:JDK8改进了`Fork/Join`框架和`Parallel Streams`,使得多核处理器环境下并行处理性能显著提升。`ConcurrentHashMap`的性能也得到了优化,提供了更好的并发性能。 9. **方法引用和构造器引用...
he Definitive Guide to Lambda Expressions Mastering Lambdas: Java ... the fork/join framework, and exceptions Examining stream performance with microbenchmarking API evolution using default methods
通常,最官方且可靠的方式是通过Oracle官方网站进行下载。访问Oracle官网的Java SE页面(https://www.oracle.com/java/technologies/javase-jdk8-downloads.html),你可以找到JDK 1.8的不同版本,包括适用于Windows...
总的来说,JDK 1.8.1的API文档包含了丰富的信息,涵盖了Lambda表达式、Stream API、日期和时间API、反射增强、Optional类、Fork/Join框架、并行流以及接口默认方法等多个关键特性,为Java开发者提供了详尽的参考指南...
Java Development Kit (JDK) 1.8是Oracle公司发布的Java编程语言的开发工具包,是Java程序员进行软件开发的基础。这个压缩包包含了两个不同操作系统的版本:Windows 64位和Mac OS英特尔64位。JDK 1.8是Java 8的重要...
Java 8 中parallelStream性能...* Java 8 中的 Fork/Join 框架:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html * JMH 框架:http://openjdk.java.net/projects/code-tools/jmh/
Java 1.8,也被称为Java 8,是Oracle公司发布的一个重要版本,它在Java 7的基础上引入了许多新特性和改进,提升了开发效率和代码的可读性。以下是关于这个版本的一些关键知识点: 1. **Lambda表达式**:这是Java 8...
此外,开发者还可以利用JDK 8的并发库(如Fork/Join框架和Stream API)来编写高效的多线程程序。 总的来说,“Linux最后一版免费32位Oracle JDK_8u191”是一个关键的开发资源,对于仍在使用32位Linux系统的开发者而...
JDK 1.7,也称为Java 7,是Oracle公司发布的Java平台标准版的一个重要版本,引入了许多新特性,如try-with-resources语句、多线程Fork/Join框架、字符串内联优化等。在CentOS 7上安装JDK 1.7,你需要执行以下步骤: ...
10. **并发改进**:`Fork/Join`框架和`Parallel Streams`的引入,提升了多核处理器环境下代码的并行性能。 通过深入学习和掌握JDK 8 API文档中的这些特性,开发者能够更好地利用Java 8的新功能,提高代码的效率和可...
3. **Fork/Join框架**:Java 7引入了一个并行计算框架,基于Fork/Join模型。它使得编写能够有效利用多核处理器的复杂任务分解变得容易。Fork/Join框架通过将大任务拆分为小任务并递归处理,实现了并行计算,提高了...
Fork/Join框架通过分治策略优化了大规模计算任务,而Parallel Streams则利用多核处理器的并行能力,自动将流操作转化为并行执行,大大提升了代码执行速度。 "模块系统"章节介绍了Jigsaw项目,这是JDK 1.8引入的全新...
Java 8是Oracle公司推出的一个重大更新版本,它引入了许多创新特性和改进,极大地提升了Java开发者的工作效率。这个"Java8 API.rar"压缩包包含了Java 8的官方API文档,对于学习和使用Java 8的新特性,以及查阅相关类...
Java 7是一个重要的Java平台版本,引入了许多新特性,如try-with-resources语句、多线程Fork/Join框架、动态类型语言支持以及字符串内联优化等。 压缩包内的"readme.txt"文件通常包含有关软件的说明、安装指南或...
JDK 1.8是Oracle公司发布的Java的一个重要版本,它的发布标志着Java SE 8的诞生。这个版本在Java社区中广受欢迎,因其稳定性和丰富的功能,许多企业和开发者至今仍在使用。 首先,JDK 1.8引入了Lambda表达式,这是...
`Fork/Join`框架用于执行复杂的分治算法,而`Parallel Streams`则利用多核处理器的优势,自动将流操作并行化,提升计算性能。 为了优化垃圾回收,JDK 1.8默认使用G1垃圾收集器,这是一种并行且低暂停时间的垃圾收集...
【描述】指出,这个源码工程是“纯官方版”,意味着它直接来源于Oracle或其他官方渠道,未经任何第三方修改。由于官方通常只提供预编译的二进制版本的JDK,而不是源代码,因此,这个压缩包提供了一个独特的途径,让...
综上所述,JDK1.8_65是Java开发的一个关键版本,它带来了许多创新和改进,包括Lambda表达式、Stream API、方法引用、接口默认方法、Fork/Join框架、CompletableFuture、类型推断增强以及新的日期时间API。...
在并发处理方面,Fork/Join框架和Parallel Streams的结合,使得开发者可以轻松利用多核处理器的优势,实现高效的并行计算。Fork/Join框架将大任务拆分为小任务,然后并行执行,最后再合并结果。 接口默认方法是1.8...