一个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<Integer> result = fjp.submit(task); try { int a = result.get(); System.out.println(a); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
class Task extends RecursiveTask<Integer>{ 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; } }
1. ForkJoinWorkerThread 的execTask方法(解决自己ForkJoinWorkerThread 的task调用)
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 } }
当execTask循环跳出,会执行scan方法,尝试从其他的ForkJoinWorkerThread中取出ForkJoinTask 然后调用execTask方法
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()方法中调用,整体处理过程还是很符合逻辑的。