【AQS框架扩展】Oracle官方教程之Fork/Join
来源:互联网 发布:sqlserver 物化视图 编辑:程序博客网 时间:2024/06/05 19:49
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
一节。
- 【AQS框架扩展】Oracle官方教程之Fork/Join
- Oracle官方教程之Fork/Join
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- Fork/join框架之ForkJoinPool
- Fork/join框架之ForkJoinPool
- Java线程之fork/join框架
- Fork/Join框架之双端队列
- 并行编程之Fork/Join框架
- Java多线程之fork/join框架详解
- JDK7新特性之fork/join框架
- java并发 java7之fork-join框架
- Fork/Join框架之双端队列
- java并发之Fork/Join框架
- Java多线程之fork/join框架详解
- Java线程之fork/join框架
- Java并发之Fork-Join框架
- mysql主从配置过程记录
- [PAT-乙级]1012.数字分类
- C#---对字符串的移除,替换,提取,切除空格,查索引
- linux入侵日志记录清除
- 关于容器
- 【AQS框架扩展】Oracle官方教程之Fork/Join
- Unity的学习步骤
- 排序算法
- 利用FPGA实现超声测距(Verilog HDL)
- 计时函数总结
- AsyncTask___网路请求使用AsyncTask
- UVALive3093 POJ2105 ZOJ2482 IP Address
- (个人)AR电子书系统创新实训第一周(2)
- haut 1273: 年终奖金(区间DP)@