Oracle官方教程之Fork/Join
原文链接,译文链接,译者:Zach,校对:郑旭东
fork/join框架是ExecutorService
接口的一种具体实现,目的是为了帮助你更好地利用多处理器带来的好处。它是为那些能够被递归地拆解成子任务的工作类型量身设计的。其目的在于能够使用所有可用的运算能力来提升你的应用的性能。
类似于ExecutorService
接口的其他实现,fork/join框架会将任务分发给线程池中的工作线程。fork/join框架的独特之处在与它使用工作窃取(work-stealing)算法。完成自己的工作而处于空闲的工作线程能够从其他仍然处于忙碌(busy)状态的工作线程处窃取等待执行的任务。
fork/join框架的核心是ForkJoinPool
类,它是对AbstractExecutorService
类的扩展。ForkJoinPool
实现了工作偷取算法,并可以执行ForkJoinTask
任务。
基本使用方法
使用fork/join框架的第一步是编写执行一部分工作的代码。你的代码结构看起来应该与下面所示的伪代码类似:
1
|
if (当前这个任务工作量足够小)
|
2
|
直接完成这个任务
|
3
|
else
|
4
|
将这个任务或这部分工作分解成两个部分
|
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;
|
03
|
private int mStart;
|
04
|
private int mLength;
|
05
|
private int [] mDestination;
|
06
|
07
|
// Processing window size; should be odd.
|
08
|
private int mBlurWidth = 15 ;
|
09
|
10
|
public ForkBlur( int [] src, int start, int length, int [] dst) {
|
11
|
mSource = src;
|
12
|
mStart = start;
|
13
|
mLength = length;
|
14
|
mDestination = dst;
|
15
|
}
|
16
|
17
|
protected void computeDirectly() {
|
18
|
int sidePixels = (mBlurWidth - 1 ) / 2 ;
|
19
|
for ( int index = mStart; index < mStart + mLength; index++) {
|
20
|
// Calculate average.
|
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 ),
|
24
|
mSource.length - 1 );
|
25
|
int pixel = mSource[mindex];
|
26
|
rt += ( float )((pixel & 0x00ff0000 ) >> 16 )
|
27
|
/ mBlurWidth;
|
28
|
gt += ( float )((pixel & 0x0000ff00 ) >> 8 )
|
29
|
/ mBlurWidth;
|
30
|
bt += ( float )((pixel & 0x000000ff ) >> 0 )
|
31
|
/ mBlurWidth;
|
32
|
}
|
33
|
34
|
// Reassemble destination pixel.
|
35
|
int dpixel = ( 0xff000000 ) |
|
36
|
((( int )rt) << 16 ) |
|
37
|
((( int )gt) << 8 ) |
|
38
|
((( int )bt) << 0 );
|
39
|
mDestination[index] = dpixel;
|
40
|
}
|
41
|
}
|
接下来你需要实现父类中的compute()
方法,它会直接执行模糊处理,或者将当前的工作拆分成两个更小的任务。数组的长度可以作为一个简单的阀值来判断任务是应该直接完成还是应该被拆分。
01
|
protected static int sThreshold = 100000 ;
|
02
|
03
|
protected void compute() {
|
04
|
if (mLength < sThreshold) {
|
05
|
computeDirectly();
|
06
|
return ;
|
07
|
}
|
08
|
09
|
int split = mLength / 2 ;
|
10
|
11
|
invokeAll( new ForkBlur(mSource, mStart, split, mDestination),
|
12
|
new ForkBlur(mSource, mStart + split, mLength - split,
|
13
|
mDestination));
|
14
|
}
|
如果前面这个方法是在一个RecursiveAction
的子类中,那么设置任务在ForkJoinPool
中执行就再直观不过了。通常会包含以下一些步骤:
- 创建一个表示所有需要完成工作的任务。
1
// source image pixels are in src
2
// destination image pixels are in dst
3
ForkBlur fb =
new
ForkBlur(src,
0
, src.length, dst);
- 创建将要用来执行任务的
ForkJoinPool
。1
ForkJoinPool pool =
new
ForkJoinPool();
- 执行任务。
1
pool.invoke(fb);
想要浏览完成的源代码,请查看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
一节。
Oracle官方教程之Fork/Join相关推荐
- [SV]SystemVerilog進程之fork join专题详解及案例分析
SystemVerilog進程之fork...join专题详解及案例分析 目錄 一.fork-join 1.1.fork join example, 二.fork-join_ ...
- Firefly官方教程之Netconnect使用文档
1.distributed说明 该模块包含了服务端与客户端通信的一些处理方法,包括发送数据的封装,协议头的封装,tcp通信时进行分包,处理粘包问题. 2.结构解析 LiberateFactory,协议 ...
- Struts2 官方教程之Struts Tags(六)——Generic Tags(Control Tags )
开头要说的:在早期的应用开发中,表现层Jsp页面主要使用Jsp脚本来控制输出.这样,在Jsp中嵌套了java脚本,这种方式不管是可读性还是可维护性都很差,几乎使Jsp成为Java的子集.从Jsp1.1 ...
- Struts2 官方教程之Struts Tags(八)——UI Tags(Themes and Templates)
UI标签是用来生成Web界面,或者为Web界面提供某些功能支持的标签,比如:表单标签就是把各种途径获取的需要展示的数据,通过动态生成HTML的形式展示到界面上. UI标签分成如下几种: Form Ta ...
- Java 7:满足Fork / Join框架
JSR-166(y)是Java 7中包含的此新功能的正式名称.如果您发现名称中有一个" y",这是因为自Java 5起就添加了JSR-166(并发实用程序) ,但它不会就此停止,因 ...
- Oracle(11g)数据库教程之十:Oracle操作题 (复习课)
Oracle(11g)数据库教程之十:Oracle操作题 (复习课) 操作题 Sutdent表的定义 字段名 字段描述 数据类型 主键 非空 Id 学号 INT(10) 是 是 Name 姓名 VAR ...
- 视频教程-Oracle从入门到精通全套视频教程之SQL与PLSQL(四)-Oracle
Oracle从入门到精通全套视频教程之SQL与PLSQL(四) Oracle DBA,熟悉Unix操作系统,精通Oracle数据库. 曾任职某大型金融IT公司,负责银行领域数据库构建与运维,维护大量银 ...
- 教你用Java7的Fork/Join框架开发高并发程序
摘要:Fork/Join框架位于J.U.C(java.util.concurrent)中,是Java7中提供的用于执行并行任务的框架,其可以将大任务分割成若干个小任务,最终汇总每个小任务的结果后得到最 ...
- java fork_浅谈Java的Fork/Join并发框架
前几天有写到整合并发结果的文章,于是联想到了Fork/Join.因为在我看来整合并发结果其实就是Fork/Join中的Join步骤.所以今天我就把自己对Fork/Join一些浅显的理解记录下来. 1. ...
最新文章
- ArcGIS对AutoCAD操作的图文教程
- ASP.NET WebApi OWIN 实现 OAuth 2.0
- tp模型和数据库操作方法
- -bash: ulimit: pipe size: cannot modify limit: Invalid argument
- freecodecamp_为什么您一定要参与freeCodeCamp的一个研究小组
- nginx-exporter安装使用
- “我哥毕业1年,做Python挣了50W!”网友:吹得太少...
- python sub 第三次_Python学习的第三次的总结
- 修改百度搜索结果的标题
- linux 下mysql忘记密码或者安装好linux后不知道mysql初始密码解决方案
- PyTorch - 数据集介绍(mnist、CIFAR10、CIFAR100)
- VB.net:VB编程语言/VB.net语言编程的简介、IDE安装、学习路线(几十项案例代码实现)之详细攻略
- php 滑块验证,实现一个滑块验证功能
- 明御安全网关(IPS)批量导入黑名单IP
- php 计算壬子,壬子日是哪一天,壬子日怎么算
- 健康体检管理系统源码 运营级PEIS系统源码 PEIS健康体检系统源码 PEIS源码 B/S架构开发
- ASP计算周开始和一年有多少周及某年第一周开始日期
- Windows10 邮箱批量导入联系人
- 卖场型旗舰店好入驻吗?需要什么资料?
- Win10桌面图标没有办法拖动(可以选中可以打开可以删除新建等操作但是不能拖动)
热门文章
- DotNet关键知识点——WCF篇(六)
- 【C++】多线程与异步编程【四】
- 【C++】【一】结构体数组
- android AIDL IPC深入分析
- Varnish Cache 3.0.0安装
- Memcached在大型网站中应用
- linux的strace命令
- Hessian源码分析(java)
- 开源库jemalloc简介
- 概率论中伯努利分布(bernoulli distribution)介绍及C++11中std::bernoulli_distribution的使用