ForkJoinPool 框架主要类:
ForkJoinPool 实现ForkJoin的线程池 - ThreadPool
- ForkJoinWorkerThread 实现ForkJoin的线程
ForkJoinTask<V> 一个描述ForkJoin的抽象类 Runnable/Callable
- RecursiveAction 无返回结果的ForkJoinTask实现Runnable
- RecursiveTask<V> 有返回结果的ForkJoinTask实现Callable
- CountedCompleter<T> 在任务完成执行后会触发执行一个自定义的钩子函数
ForkJoinPool 实现了Executor Service 接口
- ExecutorService 是Java Executor框架的基础类
- 其他ExecutorService的实现执行Runnable或Callables任务
- ForkJoinPool执行ForkJoinTasks任务
可以通过Executors. newWorkStealPool创建ForkJoinPool
ForkJoinPool任务提交方式:
-
public void execute(ForkJoinTask<?> task)
public void execute(Runnable task)
-
public <T> T invoke(ForkJoinTask<T> task)
-
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
-
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)
public <T> ForkJoinTask<T> submit(Callable<T> task)
public <T> ForkJoinTask<T> submit(Runnable task, T result)
public ForkJoinTask<?> submit(Runnable task)
ForkJoinTask主要包括两个方法分别实现任务的分拆与合并:
fork()类似于Thread.start(),但是它并不立即执行任务,而是将任务放入工作队列中。
跟Thread.join()不同,ForkJoinTask的join()方法并不简单的阻塞线程,利用工作线程运行其他任务,当一个工作线程中调用join(),它将处理其他任务,直到注意到目标子任务已经完成。
ForkJoinTask有3个子类:
RecursiveAction
无返回值的任务
RecursiveTask
有返回值的任务
CountedCompleter
完成任务后将触发其他任务
- 还是之前的数组求和的例子
class LongSum extends RecursiveTask<Long> {
static final int SEQUENTIAL_THRESHOLD = 1000;
private int low;
private int high;
private int[] array;
LongSum(int[] arr, int lo, int hi) {
this.array = arr;
this.low = lo;
this.high = hi;
}
@Override
protected Long compute() {
//System.out.println(Thread.currentThread().getName());
if (high - low <= SEQUENTIAL_THRESHOLD) {
long sum = 0;
for (int i = low; i < high; ++i) {
sum += array[i];
}
return sum;
} else {
int mid = low + (high - low) / 2;
LongSum left = new LongSum(array, low, mid);
LongSum right = new LongSum(array, mid, high);
left.fork();
long rightAns = right.compute();
long leftAns = left.join();
return leftAns + rightAns;
}
}
}
public class LongSumMain {
static long calcSum;
public static void main(String[] args) throws Exception {
int[] array = Utils.buildRandomIntArray(20000000);
calcSum = seqSum(array);
System.out.println("seq sum=" + calcSum);
LongSum ls = new LongSum(array, 0, array.length);
ForkJoinPool fjp = new ForkJoinPool(4); // with number of threads to use
ForkJoinTask<Long> result = fjp.submit(ls);
System.out.println("forkjoin sum=" + result.get());
fjp.shutdown();
}
static long seqSum(int[] array) {
long sum = 0;
for (int i = 0; i < array.length; ++i)
sum += array[i];
return sum;
}
}
- 里面很好的思想就是,一半的程序可以交由当前线程完成,不需要也另外开一个线程去处理。例子中每次分左半部分和右半部分,左半部分可以开线程去处理,而右半部分就可以当前线程来处理。
- RecursiveAction的简单应用