错误程序
public class Calculator extends RecursiveTask {
private static final int THRESHOLD = 100;
private int start;
private int end;
public Calculator(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
if((start - end) < THRESHOLD){
for(int i = start; i< end;i++){
sum += i;
}
}else{
int middle = (start + end) /2;
Calculator left = new Calculator(start, middle);
Calculator right = new Calculator(middle + 1, end);
left.fork();
right.fork();
sum = left.join() + right.join();
}
return sum;
}
}
(1)fork
1.基本作用
将任务放入任务队列队尾
2.源码
public final ForkJoinTask fork() {
((ForkJoinWorkerThread) Thread.currentThread())
.pushTask(this);
return this;
}
该方法属于:ForkJoinTask,也就是说this指向任务本身,将任务添加到任务队列末尾
因为运行ForkJoinTask的线程就是ForkJoinWorkerThread,所以可以调用其中的pushTask方法
/**
* Pushes a task. Call only from this thread.
*
* @param t the task. Caller must ensure non-null.
*/
final void pushTask(ForkJoinTask> t) {
ForkJoinTask>[] q; int s, m;
if ((q = queue) != null) { // ignore if queue removed
long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE;
UNSAFE.putOrderedObject(q, u, t);
queueTop = s + 1; // or use putOrderedInt
if ((s -= queueBase) <= 2)
pool.signalWork();
else if (s == m) //扩容用
growQueue();
}
}
其中有个成员变量queue,用来存储和本线程对应的任务队列
定义:
ForkJoinTask>[] queue;
protected void onStart() {
queue = new ForkJoinTask>[INITIAL_QUEUE_CAPACITY];
....
}
接着继续看pushTask
if ((s -= queueBase) <= 2)
pool.signalWork();
就是说当任务队列中只有一个任务时,从线程池中调用线程执行
(2)join
1.基本作用
阻塞当前线程,直到本任务执行完毕(相当于ForkJoinTask版的Thread.join)
2.源码
public final V join() {
if (doJoin() != NORMAL)
return reportResult();
else
return getRawResult();
}
主要是为了看返回值,接着看doJoin
private int doJoin() {
Thread t; ForkJoinWorkerThread w; int s; boolean completed;
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
if ((s = status) < 0)
return s;
if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
try {
completed = exec();
} catch (Throwable rex) {
return setExceptionalCompletion(rex);
}
if (completed)
return setCompletion(NORMAL);
}
return w.joinTask(this);
}
else
return externalAwaitDone();
}
这里先通过status判断状态
volatile int status; // accessed directly by pool and workers
private static final int NORMAL = -1;
private static final int CANCELLED = -2;
private static final int EXCEPTIONAL = -3;
private static final int SIGNAL = 1;
也就是说<0的是已经执行完毕的,
这对于窃取非常重要
然后通过unpushTask取任务然后执行,看下unpushTask
final boolean unpushTask(ForkJoinTask> t) {
ForkJoinTask>[] q;
int s;
if ((q = queue) != null && (s = queueTop) != queueBase &&
UNSAFE.compareAndSwapObject
(q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
queueTop = s; // or putOrderedInt
return true;
}
return false;
}
注意其中的
--s,也就是
说是从队列尾取的任务
(3)分析
left.fork();
right.fork();
sum = left.join() + right.join();
由上面可知,这段代码的意思就是:
1.把left放入任务队列,right放入任务队列。此时right在队尾,left在倒数第二个
2.left.join(),因为当前right在队尾,所以说取不出来!!!因而线程就会阻塞
正确的是调用invokeAll,看下invokeAll
public static void invokeAll(ForkJoinTask> t1, ForkJoinTask> t2) {
t2.fork();
t1.invoke();
t2.join();
}
也就是说先把t2加入队列中,然后直接执行t1,接着对t2执行join
对应上例就是:把right放入队列尾部,然后left开始执行,最后对right进行join,直到left执行完毕才能执行(当然right可能被其他线程窃取,这样通过状态判断就直接返回了)
更一般的
public static void invokeAll(ForkJoinTask>... tasks) {
Throwable ex = null;
int last = tasks.length - 1;
for (int i = last; i >= 0; --i) {
ForkJoinTask> t = tasks[i];
if (t == null) {
if (ex == null)
ex = new NullPointerException();
}
else if (i != 0)
t.fork();
else if (t.doInvoke() < NORMAL && ex == null)
ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
ForkJoinTask> t = tasks[i];
if (t != null) {
if (ex != null)
t.cancel(false);
else if (t.doJoin() < NORMAL && ex == null)
ex = t.getException();
}
}
if (ex != null)
UNSAFE.throwException(ex);
}
可以看到 i != 0 才进行fork,也就是说队列中第一个都是直接执行的,其他的以此fork,fork之后的任务之后进行join
(4)invoke
1.基本作用
直接执行任务
2.源码
public final V invoke() {
if (doInvoke() != NORMAL)
return reportResult();
else
return getRawResult();
}
再看下doInvoke
private int doInvoke() {
int s; boolean completed;
if ((s = status) < 0)
return s;
try {
completed = exec();
} catch (Throwable rex) {
return setExceptionalCompletion(rex);
}
if (completed)
return setCompletion(NORMAL);
else
return doJoin();
}
其中的exec()在RecursiveTask中
protected final boolean exec() {
result = compute();
return true;
}
在RecursiveAction中
protected final boolean exec() {
compute();
return true;
}
也就是说直接执行了