原文链接,译文链接,译者:Zach,校对:郑旭东
fork/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 { |
10 |
publicForkBlur( [] src, start,monospace!important; font-size:1em!important; direction:ltr!important; display:inline!important; background:none!important">length,monospace!important; font-size:1em!important; direction:ltr!important; display:inline!important; background:none!important">[] dst) { |
16 |
17 |
protectedvoid computeDirectly() { |
18 |
sidePixels = (mBlurWidth - 1 ) / 2 19 |
for( index = mStart; index < mStart + mLength; index++) { |
22 |
mi = -sidePixels; mi <= sidePixels; mi++) { |
23 |
mindex = Math.min(Math.max(mi + index,), |
25 |
pixel = mSource[mindex]; |
26 |
rt += ()((pixel & 0x00ff0000 ) >> 16 ) |
28 |
gt += (0x0000ff00 8 29 |
30 |
bt += (0x000000ff 31 |
32 |
} |
33 |
34 |
// Reassemble destination pixel. |
35 |
dpixel = (0xff000000 ) | |
36 |
((()rt) << ) | |
37 |
)gt) <<38 |
)bt) <<39 |
mDestination[index] = dpixel; |