Java并发包:Java Fork and Join using ForkJoinPool
来源:互联网 发布:php框架有哪些 编辑:程序博客网 时间:2024/05/23 18:33
文章译自:http://tutorials.jenkov.com/java-util-concurrent/index.html
抽空翻译了一下这个教程的文章,后面会陆续放出,如有不妥,请批评指正。
转自请注明出处。
ForkJoinPool是在java7中增加的。ForkJoinPool类似于Java ExecutorService,但是有一个不同。ForkJoinPool使得把它的任务切分成为一些小的任务然后提交给ForkJoinPool执行是很容易的。任务可以被不断的切分成子任务,只要任务是可以被切分的。这也许听起来很抽象,因此在教程中我将解释ForkJoinPool的工作原理,以及它是如何拆分任务的。
Fork and Join Explained
在说ForkJoinPool之前,我想先说说fork and Join的一般工作原理。
Fork and join原理包含递归执行的的两步,下面是fork and join以下这两步。
- Fork
使用fork and join原理,一个任务可以被分成许多子任务,这些子任务可以不发执行。下面是图示:
通过将任务拆分成许多子任务,每个子任务就可以在多个cup上并行执行,或者在线程上并发执行。
如果给定的任务是足够大的,那么这个任务会被合理拆分成许多的子任务。拆分任务也是一种开销。因此对于少量的工作,这种开销也许比通过执行每个子任务来加速实现任务的花销更多(就是拆分任务得不偿失)。
有一个将任务拆分成多少子任务的限制,我们称这个限制为阈。拆分成多少任务由一个合理的阈值决定。这很大程度上依赖你需要完成那类的工作。
- join
当一任务被拆分成了不同的子任务后,任务会等待直到所有的子任务执行完毕。
一旦所有子任务执行完毕,任务会join(merge)所有的结果为一个结果。下面是图示:
当然,不是所有的任务都会有返回结果。
The ForkJoinPool
ForkJoinPool是一种特殊的线程池,被设计用来良好的进行fork-and-join task splitting工作,ForkJoinPool在java.util.package包中,因此全类名是java.util.concurrent.ForkJoinPool.
创建一个ForkJoinPool
使用ForkJoinPool的构造函数来创建它,传递一个参数的时候,指定的是你希望的并发级别。并发级别表示在任务传递给ForkJoinPool时,你想有多少线程或者cpu并发工作。下面是创建ForkJoinPool的实例:
ForkJoinPool forkJoinPool = new ForkJoinPool(4);
这个例子中创建了一个并发级别为4的ForkJoinPool。
提交任务给ForkJoinPool
你提交任务到ForkJoinPool类似于提交任务到ExecutorService。你可以提交两类任务。第一种是任务没有任何返回结果(an “action”),另一种是可以返回结果(a “task”)。RecursiveAction和RecursiveTask这个两个类代表这两种任务。下面的部分将阐述如何使用这两类任务以及如何提交他们。
RecursiveAction
RecursiveAction是没有返回值的任务。它仅仅做一些工作,例如,将数据写入磁盘,然后退出。
RecursiveAction也许仍需要将任务拆分成子任务,然后在不同的线程或者cup上执行。
你需要继承实现RecursiveAction。下面是一个例子:
import java.util.ArrayList;import java.util.List;import java.util.concurrent.RecursiveAction;public class MyRecursiveAction extends RecursiveAction { private long workLoad = 0; public MyRecursiveAction(long workLoad) { this.workLoad = workLoad; } @Override protected void compute() { //if work is above threshold, break tasks up into smaller tasks if(this.workLoad > 16) { System.out.println("Splitting workLoad : " + this.workLoad); List<MyRecursiveAction> subtasks = new ArrayList<MyRecursiveAction>(); subtasks.addAll(createSubtasks()); for(RecursiveAction subtask : subtasks){ subtask.fork(); } } else { System.out.println("Doing workLoad myself: " + this.workLoad); } } private List<MyRecursiveAction> createSubtasks() { List<MyRecursiveAction> subtasks = new ArrayList<MyRecursiveAction>(); MyRecursiveAction subtask1 = new MyRecursiveAction(this.workLoad / 2); MyRecursiveAction subtask2 = new MyRecursiveAction(this.workLoad / 2); subtasks.add(subtask1); subtasks.add(subtask2); return subtasks; }}
例子非常的简单。MyRecursiveAction虚构了一个workLoad作为构造函数的参数。如果workLoad高于特定阈值,工作将被拆分成许多子任务,如果workLoad低于特定阈值,工作将会由MyRecursiveAction自己执行。
你可以像下面这样安排一个myrecursiveaction执行:
MyRecursiveAction myRecursiveAction = new MyRecursiveAction(24);forkJoinPool.invoke(myRecursiveAction);
RecursiveTask
RecursiveTask是一种有返回结果的任务。它也可以将任务拆分成许多小的任务,同时和并这些子任务的结果到一个结果。拆分和合并可能发生在几个层次上。下面是一个RecursiveTask例子:
import java.util.ArrayList;import java.util.List;import java.util.concurrent.RecursiveTask;public class MyRecursiveTask extends RecursiveTask<Long> { private long workLoad = 0; public MyRecursiveTask(long workLoad) { this.workLoad = workLoad; } protected Long compute() { //if work is above threshold, break tasks up into smaller tasks if(this.workLoad > 16) { System.out.println("Splitting workLoad : " + this.workLoad); List<MyRecursiveTask> subtasks = new ArrayList<MyRecursiveTask>(); subtasks.addAll(createSubtasks()); for(MyRecursiveTask subtask : subtasks){ subtask.fork(); } long result = 0; for(MyRecursiveTask subtask : subtasks) { result += subtask.join(); } return result; } else { System.out.println("Doing workLoad myself: " + this.workLoad); return workLoad * 3; } } private List<MyRecursiveTask> createSubtasks() { List<MyRecursiveTask> subtasks = new ArrayList<MyRecursiveTask>(); MyRecursiveTask subtask1 = new MyRecursiveTask(this.workLoad / 2); MyRecursiveTask subtask2 = new MyRecursiveTask(this.workLoad / 2); subtasks.add(subtask1); subtasks.add(subtask2); return subtasks; }}
这个例子和上面RecursiveAction的例子是类似的,不同的是有返回值。
MyRecursiveTask类继承自 RecursiveTask< Long> , RecursiveTask< Long> 意味着从任务返回的结果是一个长整形(Long)。
MyRecursiveTask的例子也是将任务拆分成多个子任务,然后使用fork()方法来执行这些子任务。
此外,这个例子通过调用每个子任务的join()方法,接收每个子任务返回的结果。子任务的结果会合并到一个总的结果,然后被返回。这种合并子任务结果的情况同时在递归过程中发生。
你可以像下面这样使用RecursiveTask:
MyRecursiveTask myRecursiveTask = new MyRecursiveTask(128);long mergedResult = forkJoinPool.invoke(myRecursiveTask);System.out.println("mergedResult = " + mergedResult);
ForkJoinPool 的评论文章
对于java7中的新增的ForkJoinPool,并不是每个都是高兴的。在搜索关于ForkJoinPool的体验和意见时,我遇到了下面的评论文章:
A Java Fork-Join Calamity(http://coopsoft.com/ar/CalamityArticle.html)。
在你打算在你的项目中使用ForkJoinPool之前,这篇文章是非常值得一读的。
- Java并发包:Java Fork and Join using ForkJoinPool
- java并发包:fork/join
- Java fork join ForkJoinPool 用法例子
- java并发包学习系列:fork/join
- Java并发-Fork/Join框架
- 【Java并发编程】Fork/Join
- Java并发框架Fork/Join
- Fork and Join: Java编写并发程序(重要)
- Fork and Join(Java并发编程的思路)
- ForkJoinPool/fork/join
- Fork/join框架之ForkJoinPool
- Fork/join框架之ForkJoinPool
- java并发 java7之fork-join框架
- 乱弹java并发(九)-- fork/join
- Java并发编程--Fork/Join框架使用
- java并发之Fork/Join实例
- Java并发基础(九)-Fork/Join框架
- java并发之Fork/Join框架
- CodeForces 197A-Plate Game
- Activity生命周期
- linux安卓开发,解决 java 摆脱, openjdk 的方法
- wxpython在python 3.X下的安装方法
- 安卓VIEW的绘制过程
- Java并发包:Java Fork and Join using ForkJoinPool
- 同余和模运算
- 解决ADT不会提示代码的问题
- web前端知识总结-BOM和DOM
- Hdu3037 Saving Beans Lucas定理
- 学习笔记 cocos2d-x 2.x到3.x的改动与区别
- iOS/mac开发的一些知名个人博客
- MagicNumber求平方根倒数
- Lucas定理模板