一个ForkJoinPool 对应多个ForkJoinWorkerThread
一个ForkJoinWorkerThread 对应多个ForkJoinTask
以一个简单的求和Task为例:
public class ForkJoinTest {
public static void main(String[] args) {
ForkJoinPool fjp = new ForkJoinPool(2);
Task task = new Task(0, 8);
Future result = fjp.submit(task);
try {
int a = result.get();
System.out.println(a);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
class Task extends RecursiveTask{
public static final int THRESHOLD = 2;
private int start;
private int end;
public Task(int start, int end){
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
boolean canCompute = (end - start) <= THRESHOLD;
if(canCompute){
for(int i=start; i <= end; i++){
sum += i;
}
} else{
int middle = (start + end)/2;
Task left = new Task(start, middle);
Task right = new Task(middle, end);
invokeAll(left, right);
int leftResult = left.join();
int rightResult = right.join();
sum = leftResult + rightResult;
}
return sum;
}
}
final void execTask(ForkJoinTask> t) {
currentSteal = t;
for (;;) {
if (t != null)
t.doExec();
if (queueTop == queueBase)
break;
t = locallyFifo ? locallyDeqTask() : popTask();
}
++stealCount;
currentSteal = null;
}
这里就是执行task,当执行完成会取出当前ForkJoinWorkerThread的下一个ForkJoinTask,如果已经区空了就会跳出循环
2. ForkJoinWorkerThread 的scan方法(解决别人以及自己ForkJoinWorkerThread的task调用)
private boolean scan(ForkJoinWorkerThread w, int a) {
int g = scanGuard; // mask 0 avoids useless scans if only one active
int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
ForkJoinWorkerThread[] ws = workers;
if (ws == null || ws.length <= m) // staleness check
return false;
for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
ForkJoinWorkerThread v = ws[k & m];
if (v != null && (b = v.queueBase) != v.queueTop &&
(q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
long u = (i << ASHIFT) + ABASE;
if ((t = q[i]) != null && v.queueBase == b &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
int d = (v.queueBase = b + 1) - v.queueTop;
v.stealHint = w.poolIndex;
if (d != 0)
signalWork(); // propagate if nonempty
w.execTask(t);
}
r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
return false; // store next seed
}
else if (j < 0) { // xorshift
r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
}
else
++k;
}
if (scanGuard != g) // staleness check
return false;
else { // try to take submission
ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
if ((b = queueBase) != queueTop &&
(q = submissionQueue) != null &&
(i = (q.length - 1) & b) >= 0) {
long u = (i << ASHIFT) + ABASE;
if ((t = q[i]) != null && queueBase == b &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
queueBase = b + 1;
w.execTask(t);
}
return false;
}
return true; // all queues empty
}
}
3. ForkJoinTask的invokeAll方法(解决如何分配task的问题)
public static void invokeAll(ForkJoinTask> t1, ForkJoinTask> t2) {
t2.fork();
t1.invoke();
t2.join();
}
step 1:把t2压入当前ForkJoinWorkerThread的queue中,要么当前ForkJoinWorkerThread会去消费,要么会有空闲的ForkJoinWorkerThread去消费
step 2:当前ForkJoinWorkerThread继续执行t1
step3: 当前ForkJoinWorkerThread等待t2的完成
invokeAll方法往往是在compute()方法中调用,整体处理过程还是很符合逻辑的。