原理解析:fork分解,join结合。这个框架的本质是将一个任务分解成多个子任务,每个子任务用单独的线程去处理。这里用到了递归的思想。框架的结构图可以参考

为巴彦淖尔等地区用户提供了全套网页设计制作服务,及巴彦淖尔网站建设行业解决方案。主营业务为网站建设、成都做网站、巴彦淖尔网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
图片来源(http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html)
使用fork/join 框架很简单,
1.实现子问题的一般求解算法
2.如何分解问题
3.继承 RecursiveAction ,实现compute()方法
伪代码代码
- Result solve(Problem problem) {
 - if (problem is small)
 - directly solve problem
 - else {
 - split problem into independent parts
 - fork new subtasks to solve each part
 - join all subtasks
 - compose result from subresults
 - }
 
这里我通过一个改进的二分查找来讲解fork/join的使用。(后面才发现,选用这个案例是非常失败的,因为二分查找的时间是logn,而创建线程的开销更大,这样并不能体现多线程二分查找的优势,所以这个代码不具有实用性,只是为了说明如何使用框架:)
代码如下:
BinarySearchProblem.java
Java代码
- package testjdk7;
 - import java.util.Arrays;
 - /**
 - * @author kencs@foxmail.com
 - */
 - public class BinarySearchProblem {
 - private final int[] numbers;
 - private final int start;
 - private final int end;
 - public final int size;
 - public BinarySearchProblem(int[] numbers,int start,int end){
 - this.numbers = numbers;
 - this.start = start;
 - this.end = end;
 - this.size = end -start;
 - }
 - public int searchSequentially(int numberToSearch){
 - //偷懒,不自己写二分查找了
 - return Arrays.binarySearch(numbers, start, end, numberToSearch);
 - }
 - public BinarySearchProblem subProblem(int subStart,int subEnd){
 - return new BinarySearchProblem(numbers,start+subStart,start+subEnd);
 - }
 - }
 
BiSearchWithForkJoin.java
Java代码
- package testjdk7;
 - import java.util.concurrent.ForkJoinPool;
 - import java.util.concurrent.RecursiveAction;
 - /**
 - * @author kencs@foxmail.com
 - */
 - public class BiSearchWithForkJoin extends RecursiveAction {
 - private final int threshold;
 - private final BinarySearchProblem problem;
 - public int result;
 - private final int numberToSearch;
 - public BiSearchWithForkJoin(BinarySearchProblem problem,int threshold,int numberToSearch){
 - this.problem = problem;
 - this.threshold = threshold;
 - this.numberToSearch = numberToSearch;
 - }
 - @Override
 - protected void compute() {
 - if(problem.size < threshold){ //小于阀值,就直接用普通的二分查找
 - result = problem.searchSequentially(numberToSearch);
 - }else{
 - //分解子任务
 - int midPoint = problem.size/2;
 - BiSearchWithForkJoin left = new BiSearchWithForkJoin(problem.subProblem(0, midPoint),threshold,numberToSearch);
 - BiSearchWithForkJoin right = new BiSearchWithForkJoin(problem.subProblem(midPoint+1, problem.size),threshold,numberToSearch);
 - invokeAll(left,right);
 - result = Math.max(left.result, right.result);
 - }
 - }
 - //构造数据
 - private static final int[] data = new int[1000_0000];
 - static{
 - for(int i = 0;i<1000_0000;i++){
 - data[i] = i;
 - }
 - }
 - public static void main(String[] args){
 - BinarySearchProblem problem = new BinarySearchProblem(data,0,data.length);
 - int threshold = 100;
 - int nThreads = 10;
 - //查找100_0000所在的下标
 - BiSearchWithForkJoin bswfj = new BiSearchWithForkJoin(problem,threshold,100_0000);
 - ForkJoinPool fjPool = new ForkJoinPool(nThreads);
 - fjPool.invoke(bswfj);
 - System.out.printf("Result is:%d%n",bswfj.result);
 - }
 - }
 
RecursiveTask 还可以带返回值,这里给出一段代码作为参考(斐波那契函数)
(来自http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html)
Java代码
- class Fibonacci extends RecursiveTask {
 - final int n;
 - Fibonacci(int n) {
 - this.n = n;
 - }
 - private int compute(int small) {
 - final int[] results = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
 - return results[small];
 - }
 - public Integer compute() {
 - if (n <= 10) {
 - return compute(n);
 - }
 - Fibonacci f1 = new Fibonacci(n - 1);
 - Fibonacci f2 = new Fibonacci(n - 2);
 - System.out.println("fork new thread for " + (n - 1));
 - f1.fork();
 - System.out.println("fork new thread for " + (n - 2));
 - f2.fork();
 - return f1.join() + f2.join();
 - }
 - }
 
用途
只要问题能够分解成类似子问题的,都可以使用这个框架。对于大批量的数据尤其合适
参考资料
Jdk7官网 http://openjdk.java.net/projects/jdk7/
(注:这篇文章发表时,JDK7未正式公布,可能有误差,具体以官方正式版为准)
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号