Java7中引入了一种新的并发框架-Fork/Join,Fork/Join采用分治+work-stealing的思想,Fork/Join相教于其他并发框架有其适合的使用场景:如果一个任务能够被分为多个子任务,通过组合这些子任务的结果就能获得最终结果,那么这项任务就适合用Fork/Join模式解决。
如上说述,递归问题比较适合用ForkJoin框架解决,如求Fibonacci数列的第N项值: F(n) = F(n-1) + F(n-2),实现如下:
public class ForkJoinTest {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
Fibonacci task = new Fibonacci(5);
int ans = pool.invoke(task);
System.out.println(ans);
}
static class Fibonacci extends RecursiveTask {
private int n;
public Fibonacci(int n) {
this.n = n;
}
@Override
protected Integer compute() {
System.out.println(Thread.currentThread().getName());
if(n <= 2) {
return 1;
}
try{
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Fibonacci f1 = new Fibonacci(n - 1);
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2);
f2.fork();
int ans = f1.join() + f2.join();
return ans;
}
}
}
---
ForkJoinPool-1-worker-1
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-2
ForkJoinPool-1-worker-0
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-0
ForkJoinPool-1-worker-4
5
ForkJoinPool一共有3个共有构造函数,如下:
public ForkJoinPool() {
this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism) {
this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
构造函数参数 | 含义 |
---|---|
int parallelism | 可并行级别,最小为1。Fork/Join框架根据这个级别设定并行执行的线程数,但parallelism不等于线程数。默认构造函数中将改值设为CPU的核数 |
ForkJoinWorkerThreadFactory factory | 线程创建工厂。它是一个函数式接口,需要实现一个newThread方法 |
UncaughtExceptionHandler handler | 异常处理器。处理任务中抛出的异常,默认为null |
boolean asyncMode | 是否为异步模式,默认为false,即LIFO模式。指定线程任务队列的处理方式,通常有LIFO、FIFO两种模式 |
ForkJoinPool提供了三个任务提交的方法:execute、submit和invoke:
public void execute(ForkJoinTask> task) {
if (task == null)
throw new NullPointerException();
externalPush(task);
}
public ForkJoinTask submit(ForkJoinTask task) {
if (task == null)
throw new NullPointerException();
externalPush(task);
return task;
}
public T invoke(ForkJoinTask task) {
if (task == null)
throw new NullPointerException();
externalPush(task);
return task.join();
}
execute方法和submit方法大致逻辑相同,都是先对任务做非空校验再讲任务压入ForkJoinPool中的执行队列,唯一不同的是submit会把任务对象本身返回,返回后可以通过get()方法获取执行结果。和execute方法、submit方法不同,invoke方法将任务压入队列后会执行join()方法,阻塞当前线程。
ForkJoinPool提供了一个线程创建工厂接口并提供了默认实现,通过该工厂可以创建ForkJoinWorkerThread线程
public static interface ForkJoinWorkerThreadFactory {
public ForkJoinWorkerThread newThread(ForkJoinPool pool);
}
static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new ForkJoinWorkerThread(pool);
}
}
ForkJoinWorkerThread主要有两个成员变量,一个是线程所归属的ForkJoinPool线程池,另一个是存放ForkJoinTask的任务队列,可见每个ForkJoinWorkerThread线程都维护一个任务队列,该队列提供LIFO和FIFO两种出队方式。
public class ForkJoinWorkerThread extends Thread {
final ForkJoinPool pool; // the pool this thread works in
final ForkJoinPool.WorkQueue workQueue;
...
}
public class ForkJoinPool extends AbstractExecutorService {
static final class WorkQueue {
final void push(ForkJoinTask> task) {
...
}
/**
* Takes next task, if one exists, in LIFO order. Call only
* by owner in unshared queues.
*/
final ForkJoinTask> pop() {
...
}
/**
* Takes next task, if one exists, in FIFO order.
*/
final ForkJoinTask> poll() {
...
}
}
}
shutDown(); // 执行该方法后ForkJoinPool不再接受新任务,但队列中未执行的任务和正在执行中的任务仍然可以继续执行
public void shutdown() {
checkPermission();
tryTerminate(false, true);
}
shutDownNow(); // 停止所有未执行的任务并且拒绝新任务,正在执行中的任务可继续执行
public List shutdownNow() {
checkPermission();
tryTerminate(true, true);
return Collections.emptyList();
}
awaitTermination(long timeout, TimeUnit unit); // 阻塞当前线程,直到ForkJoinPool中所有任务执行完毕
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
...
}
fork()方法判断当前线程是否是ForkJoinWorkerThread的实例,如果是则将任务压入当前线程的队列中;如果不是则将任务压入ForkJoinPool的公用线程池的执行队列中
public final ForkJoinTask fork() {
Thread t;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
((ForkJoinWorkerThread)t).workQueue.push(this);
else
ForkJoinPool.common.externalPush(this);
return this;
}
执行步骤为:
a.判断当前任务是否执行完成、取消或异常,如果是则退出
b.如果任务是CountedCompleter类型任务,则通过helpComplet完成当前队列的任务
c.非CountedCompleter任务调用tryRemoveAndExec执行任务
d.如果当前队列为空,则任务可能被偷,通过helpStealer帮助偷取者执行任务
e.再次判断当前任务的状态是否执行完成、取消或异常,如果是则退出
f.判断是否超时,如果deadline不为0且超时则退出
g.执行补偿逻辑,如果补偿成功,则阻塞一段时间
public final V join() {
int s;
if ((s = doJoin() & DONE_MASK) != NORMAL)
reportException(s);
return getRawResult();
}
private int doJoin() {
int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
return (s = status) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(w = (wt = (ForkJoinWorkerThread)t).workQueue).
tryUnpush(this) && (s = doExec()) < 0 ? s :
wt.pool.awaitJoin(w, this, 0L) :
externalAwaitDone();
}
final int awaitJoin(WorkQueue w, ForkJoinTask> task, long deadline) {
int s = 0;
if (task != null && w != null) {
ForkJoinTask> prevJoin = w.currentJoin;
U.putOrderedObject(w, QCURRENTJOIN, task);
CountedCompleter> cc = (task instanceof CountedCompleter) ?
(CountedCompleter>)task : null;
for (;;) {
if ((s = task.status) < 0)
break;
if (cc != null)
helpComplete(w, cc, 0);
else if (w.base == w.top || w.tryRemoveAndExec(task))
helpStealer(w, task);
if ((s = task.status) < 0)
break;
long ms, ns;
if (deadline == 0L)
ms = 0L;
else if ((ns = deadline - System.nanoTime()) <= 0L)
break;
else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
ms = 1L;
if (tryCompensate(w)) {
task.internalWait(ms);
U.getAndAddLong(this, CTL, AC_UNIT);
}
}
U.putOrderedObject(w, QCURRENTJOIN, prevJoin);
}
return s;
}