ForkJoin是Java7提供的原生多线程并行处理框架,其基本思想是将大任务分割成小任务,最后将小任务聚合起来得到结果。fork是分解的意思, join是收集的意思. 它非常类似于HADOOP提供的MapReduce框架,只是MapReduce的任务可以针对集群内的所有计算节点,可以充分利用集群的能力完成计算任务。ForkJoin更加类似于单机版的MapReduce。
在fork/join框架中,若某个子问题由于等待另一个子问题的完成而无法继续执行。那么处理该子问题的线程会主动寻找其他尚未运行完成的子问题来执行。这种方式减少了线程的等待时间,提高了性能。子问题中应该避免使用synchronized关键词或其他方式方式的同步。也不应该是一阻塞IO或过多的访问共享变量。在理想情况下,每个子问题的实现中都应该只进行CPU相关的计算,并且只适用每个问题的内部对象。唯一的同步应该只发生在子问题和创建它的父问题之间。
Fork/Join使用两个类完成以上两件事情:
ForkJoinTask: 我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制,ForkJoinTask实现了Future接口,可以按照Future接口的方式来使用。在ForkJoinTask类中之重要的两个方法fork和join。
fork方法用以一部方式启动任务的执行,join方法则等待任务完成并返回指向结果。在创建自己的任务是,最好不要直接继承自ForkJoinTask类,而要继承自ForkJoinTask类的子类RecurisiveTask或RecurisiveAction类
1. RecursiveAction,用于没有返回结果的任务
2. RecursiveTask,用于有返回值的任务
· ForkJoinPool:task要通过ForkJoinPool来执行,分割的子任务也会添加到当前工作线程的双端队列中,进入队列的头部。当一个工作线程中没有任务时,会从其他工作线程的队列尾部获取一个任务。
2个构造方法
ForkJoinPool(int parallelism) 创建一个包含parallelism个并行线程的ForkJoinPool。
ForkJoinPool()
以Runtime.availableProcessors()方法的返回值作为
parallelism参数来创建ForkJoinPool。
3种方式启动
异步执行
execute(ForkJoinTask)
ForkJoinTask.fork
等待获取结果
invoke(ForkJoinTask)
ForkJoinTask.invoke
执行,获取Future
submit(ForkJoinTask)
ForkJoinTask.fork()
异常处理:
ForkJoinTask在执行的时候可能会抛出异常,但是没办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常.
getException方法返回Throwable对象,如果任务被取消了则返回CancellationException。如果任务没有完成或者没有抛出异常则返回null。
if(task.isCompletedAbnormally()) {
System.out.println(task.getException());
}
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
* fork
* 对一个大数组进行并行求和的RecursiveTask
*
* 大任务可以拆成小任务,小任务还可以继续拆成更小的任务,最后把任务的结果汇总合并,得到最终结果,这种模型就是Fork/Join模型。
Java7引入了Fork/Join框架,我们通过RecursiveTask这个类就可以方便地实现Fork/Join模式。
class ForkJoinTest
extends RecursiveTask {
static final int THRESHOLD = 100;
long[] array;
int start;
int end;
ForkJoinTest(long[] array,
int start, int end) {
this.start = start ;
this.end = end ;
this.array = array;
}
@Override protected Long compute() {
if (end - start < THRESHOLD) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
println String.format('compute %d %d = %d',
start, end, sum);
} // 对于大任务, 分多线程执行
int middle = (end + start) / 2;
println String.format('split %d %d => %d %d,
%d %d', start, end, start
, middle, middle, end)
def subtask1 =
new ForkJoinTest(this.array, start, middle);
def subtask2 =
new ForkJoinTest(this.array, middle, end);
invokeAll(subtask1, subtask2)
Long subresult1 = subtask1.join();
Long subresult2 = subtask2.join();
Long result = subresult1 + subresult2;
System.out.println("result = "
+ subresult1 + " + "
+ subresult2 + " ==> "
+ result);
return result
}
public static void main(String[] args)
throws Exception {
// 创建随机数组成的数组:
long[] array = new long[400]; fillRandom(array);
// fork/join task:
ForkJoinPool fjp =
new ForkJoinPool(4);
// 最大并发数4
ForkJoinTask task =
new ForkJoinTest(array, 0, array.length);
long startTime = System.currentTimeMillis();
Long result = fjp.invoke(task);
long endTime = System.currentTimeMillis();
System.out.println("Fork/join sum: "
+ result + " in "
+ (endTime - startTime) + " ms.");
}
}
=====================
public class CountTask
extends RecursiveTask{
private volatile static int count = 0;
private int start;
private int end;
public CountTask(int start, int end) {
this.start = start;
this.end = end;
}
public static final int threadhold = 2;
@Override
protected Integer compute() {
int sum = 0;
System.out.println("开启了一条线程单独干: "
+ count++);
// 如果任务足够小, 就直接执行
boolean canCompute
= (end - start) <= threadhold;
if (canCompute) {
for (int i = start; i <= end; i++) {
sum += i;
}
}else {
//任务大于阈值, 分裂为2个任务
int middle = (start + end) / 2;
CountTask countTask1
= new CountTask(start, middle);
CountTask countTask2
= new CountTask(middle + 1, end);
// 开启线程//
countTask1.fork();//
countTask2.fork();
invokeAll(countTask1, countTask2);
Integer join1 = countTask1.join();
Integer join2 = countTask2.join();
// 结果合并
sum = join1 + join2;
}
return sum;
} // 测试
public static void main(String[] a)
throws Exception {
ForkJoinPool forkJoinPool
= new ForkJoinPool();
CountTask countTask =
new CountTask(1, 100);
ForkJoinTask result=
forkJoinPool.submit(countTask);
System.out.println(result.get());
}
}
![a43fc2b3b10260039c9a3e9bfc1eb451.png](https://i-blog.csdnimg.cn/blog_migrate/604474d6e88fcf0a99686ceccd980a25.jpeg)