Jdk1.7 JUC源码增量解析(3)-ForkJoin-非ForkJoin任务的执行过程
作者:大飞
- 这篇通过分析一个非ForkJoin(Runnable或者Callable)任务的执行过程来分析ForkJoin的相关代码,注意这里说的非ForkJoin任务实际上也是ForkJoinTask,只是没有分裂(fork)/合并(join)过程。
public static void main(String[] args) { ForkJoinPool forkJoinPool = new ForkJoinPool(); ForkJoinTask<?> task = forkJoinPool.submit(new Runnable() { @Override public void run() { System.out.println("呵呵哒~"); } }); try { task.get(); forkJoinPool.shutdown(); } catch (Exception e) { e.printStackTrace(); } }
- 首先需要创建一个ForkJoinPool,我们来看下ForkJoinPool的构造方法:
public ForkJoinPool() { this(Runtime.getRuntime().availableProcessors(), defaultForkJoinWorkerThreadFactory, null, false); } public ForkJoinPool(int parallelism) { this(parallelism, defaultForkJoinWorkerThreadFactory, null, false); } public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory, Thread.UncaughtExceptionHandler handler, boolean asyncMode) { checkPermission(); if (factory == null) throw new NullPointerException(); if (parallelism <= 0 || parallelism > MAX_ID) throw new IllegalArgumentException(); //设置并行度。 this.parallelism = parallelism; //设置工作线程工厂。 this.factory = factory; //设置线程未捕获异常处理器。 this.ueh = handler; //设置是否为异步模式。 this.locallyFifo = asyncMode; /* * 参考我们之前介绍的ctl的内容,由于ctl中的AC表示当前活动 * 工作线程数量减去并行度,所以这里要将这个信息加到ctl上。 */ long np = (long)(-parallelism); //初始化ForkJoinPool控制信息。 this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); //初始化提交任务队列。 this.submissionQueue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; /* * 这里需要根据并行度来算出工作线程数组的大小。 * 由于数组大小必须的2的幂,这里的算法是算出比 * parallelism的2倍大的最小的2的幂,但不能超过 * MAX_ID + 1(1 << 16)的数作为工作线程数组大小 */ int n = parallelism << 1; if (n >= MAX_ID) n = MAX_ID; else { // See Hackers Delight, sec 3.2, where n < (1 << 16) n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; } //创建存放工作线程的数组。 workers = new ForkJoinWorkerThread[n + 1]; this.submissionLock = new ReentrantLock(); this.termination = submissionLock.newCondition(); //生成工作线程名称前缀。 StringBuilder sb = new StringBuilder("ForkJoinPool-"); sb.append(poolNumberGenerator.incrementAndGet()); sb.append("-worker-"); this.workerNamePrefix = sb.toString(); }
ForkJoinPool中还提供了默认的工作线程工厂:
static { ... defaultForkJoinWorkerThreadFactory = new DefaultForkJoinWorkerThreadFactory(); ... } public static interface ForkJoinWorkerThreadFactory { public ForkJoinWorkerThread newThread(ForkJoinPool pool); } static class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { public ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new ForkJoinWorkerThread(pool); } }
- 创建了ForkJoinPool,下面看看将任务提交到Pool方法submit:
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) { if (task == null) throw new NullPointerException(); forkOrSubmit(task); return task; } public <T> ForkJoinTask<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); ForkJoinTask<T> job = ForkJoinTask.adapt(task); forkOrSubmit(job); return job; } public <T> ForkJoinTask<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); ForkJoinTask<T> job = ForkJoinTask.adapt(task, result); forkOrSubmit(job); return job; } public ForkJoinTask<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); ForkJoinTask<?> job; if (task instanceof ForkJoinTask<?>) // avoid re-wrap job = (ForkJoinTask<?>) task; else job = ForkJoinTask.adapt(task, null); forkOrSubmit(job); return job; }
ForkJoinPool中定义了一些列重载的submit方法,这些submit方法内部会先将Callable、Runnable包装(适配)成ForkJoinTask,然后再进行提交。看下包装的方法:
public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) { return new AdaptedCallable<T>(callable); } public static ForkJoinTask<?> adapt(Runnable runnable) { return new AdaptedRunnable<Void>(runnable, null); } public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) { return new AdaptedRunnable<T>(runnable, result); }
针对Callable会包装成一个AdaptedCallable:
static final class AdaptedCallable<T> extends ForkJoinTask<T> implements RunnableFuture<T> { final Callable<? extends T> callable; T result; AdaptedCallable(Callable<? extends T> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; } public T getRawResult() { return result; } public void setRawResult(T v) { result = v; } public boolean exec() { try { result = callable.call(); return true; } catch (Error err) { throw err; } catch (RuntimeException rex) { throw rex; } catch (Exception ex) { throw new RuntimeException(ex); } } public void run() { invoke(); } private static final long serialVersionUID = 2838392045355241008L; }
针对Runnable会包装成一个AdaptedRunnable:
static final class AdaptedRunnable<T> extends ForkJoinTask<T> implements RunnableFuture<T> { final Runnable runnable; final T resultOnCompletion; T result; AdaptedRunnable(Runnable runnable, T result) { if (runnable == null) throw new NullPointerException(); this.runnable = runnable; this.resultOnCompletion = result; } public T getRawResult() { return result; } public void setRawResult(T v) { result = v; } public boolean exec() { runnable.run(); result = resultOnCompletion; return true; } public void run() { invoke(); } private static final long serialVersionUID = 5232453952276885070L; }
所有submit方法内部最终都会调用一个forkOrSubmit方法,看下这个方法:
private <T> void forkOrSubmit(ForkJoinTask<T> task) { ForkJoinWorkerThread w; Thread t = Thread.currentThread(); if (shutdown) throw new RejectedExecutionException(); if ((t instanceof ForkJoinWorkerThread) && (w = (ForkJoinWorkerThread)t).pool == this) w.pushTask(task); else addSubmission(task); }
private void addSubmission(ForkJoinTask<?> t) { final ReentrantLock lock = this.submissionLock; lock.lock(); try { ForkJoinTask<?>[] q; int s, m; if ((q = submissionQueue) != null) { // ignore if queue removed //这步计算内存偏移地址 long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE; //将t设置到q的对应位置。(LazySet) UNSAFE.putOrderedObject(q, u, t); queueTop = s + 1; if (s - queueBase == m) //如果队列满了,扩展队列。 growSubmissionQueue(); } } finally { lock.unlock(); } //唤醒工作线程。 signalWork(); }
private void growSubmissionQueue() { ForkJoinTask<?>[] oldQ = submissionQueue; int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY; if (size > MAXIMUM_QUEUE_CAPACITY) throw new RejectedExecutionException("Queue capacity exceeded"); if (size < INITIAL_QUEUE_CAPACITY) size = INITIAL_QUEUE_CAPACITY; ForkJoinTask<?>[] q = submissionQueue = new ForkJoinTask<?>[size]; int mask = size - 1; int top = queueTop; int oldMask; if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) { for (int b = queueBase; b != top; ++b) { long u = ((b & oldMask) << ASHIFT) + ABASE; Object x = UNSAFE.getObjectVolatile(oldQ, u); if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null)) UNSAFE.putObjectVolatile (q, ((b & mask) << ASHIFT) + ABASE, x); } } }
- 现在任务已经提交到ForkJoinPool的submissionQueue中了,那么接下来任务如何被执行呢?继续往下看。
final void signalWork() { long c; int e, u; while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) & (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) { if (e > 0) { //唤醒一个等待的工作线程。 int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; if ((ws = workers) == null || //如果看到workers为null (i = ~e & SMASK) >= ws.length || //等待工作线程的下标比workers的size大。 (w = ws[i]) == null) //获取不到等待线程。 break; long nc = (((long)(w.nextWait & E_MASK)) | //将Treiber stack中下一个等待线程的信息(下标)放到控制信息上。 ((long)(u + UAC_UNIT) << 32)); //控制信息上添加一个AC计数。 if (w.eventCount == e && UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { w.eventCount = (e + EC_UNIT) & E_MASK; //累加w的等待次数。 if (w.parked) UNSAFE.unpark(w); //唤醒w。 break; } } //添加一个工作线程。 else if (UNSAFE.compareAndSwapLong (this, ctlOffset, c, (long)(((u + UTC_UNIT) & UTC_MASK) | //累加控制信息上AC和TC。 ((u + UAC_UNIT) & UAC_MASK)) << 32)) { addWorker(); //添加工作线程。 break; } } }
private void addWorker() { Throwable ex = null; ForkJoinWorkerThread t = null; try { t = factory.newThread(this); } catch (Throwable e) { ex = e; } if (t == null) { //如果发生了异常导致工作线程创建失败,需要把之前累加的到控制信息的AC和TC计数减回去。 long c; do {} while (!UNSAFE.compareAndSwapLong (this, ctlOffset, c = ctl, (((c - AC_UNIT) & AC_MASK) | ((c - TC_UNIT) & TC_MASK) | (c & ~(AC_MASK|TC_MASK))))); // 如果调用来之外部,需要将异常传递出去。 if (!tryTerminate(false) && ex != null && !(Thread.currentThread() instanceof ForkJoinWorkerThread)) UNSAFE.throwException(ex); } else t.start(); //创建成功的话,启动工作线程。 }这个方法中要注意下工作线程的创建过程,上面看到Pool会提供了默认的工作线程工厂来创建线程,看下具体过程:
static class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { public ForkJoinWorkerThread newThread(ForkJoinPool pool) { return new ForkJoinWorkerThread(pool); } }再看下ForkJoinWorkerThread的构造方法:
protected ForkJoinWorkerThread(ForkJoinPool pool) { //设置线程名称,名称由Pool的nextWorkerName方法产生。 super(pool.nextWorkerName()); //由于ForkJoinWorkerThread中有一个Pool的引用,这里设置引用。 this.pool = pool; //将自己注册到Pool里面。 int k = pool.registerWorker(this); //保存在Pool里面的下标。 poolIndex = k; //这里的eventCount初始化为工作线程在Pool中的下标取反值。 eventCount = ~k & SMASK; //设置工作模式。 locallyFifo = pool.locallyFifo; //设置线程未捕获异常处理器。 Thread.UncaughtExceptionHandler ueh = pool.ueh; if (ueh != null) setUncaughtExceptionHandler(ueh); //设置为守护线程。 setDaemon(true); }工作线程名称的生成方法在Pool中,看下:
private volatile int nextWorkerNumber; final String nextWorkerName() { for (int n;;) { if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset, n = nextWorkerNumber, ++n)) return workerNamePrefix + n; } }主要看下创建工作线程过程中,注册到Pool的过程:
final int registerWorker(ForkJoinWorkerThread w) { for (int g;;) { ForkJoinWorkerThread[] ws; //如果当前scanGuard中没有SG_UNIT标记,尝试设置SG_UNIT标记。 //这是一个加锁的过程。 if (((g = scanGuard) & SG_UNIT) == 0 && UNSAFE.compareAndSwapInt(this, scanGuardOffset, g, g | SG_UNIT)) { int k = nextWorkerIndex; try { if ((ws = workers) != null) { // ignore on shutdown int n = ws.length; if (k < 0 || k >= n || ws[k] != null) { for (k = 0; k < n && ws[k] != null; ++k) ; if (k == n) ws = workers = Arrays.copyOf(ws, n << 1); } ws[k] = w; nextWorkerIndex = k + 1; int m = g & SMASK; g = (k > m) ? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1); } } finally { scanGuard = g; } return k; } else if ((ws = workers) != null) { // help release others for (ForkJoinWorkerThread u : ws) { if (u != null && u.queueBase != u.queueTop) { if (tryReleaseWaiter()) break; } } } } }
public void run() { Throwable exception = null; try { onStart(); pool.work(this); } catch (Throwable ex) { exception = ex; } finally { onTermination(exception); } }
protected void onStart() { //初始化工作线程的任务队列。 queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; //生成工作线程的种子。 int r = pool.workerSeedGenerator.nextInt(); //确保种子不为0。 seed = (r == 0) ? 1 : r; // must be nonzero } protected void onTermination(Throwable exception) { try { //设置关闭标志。 terminate = true; //取消任务。 cancelTasks(); //从ForkJoinPool上注销当前工作线程。 pool.deregisterWorker(this, exception); } catch (Throwable ex) { // Shouldn't ever happen if (exception == null) // but if so, at least rethrown exception = ex; } finally { if (exception != null) UNSAFE.throwException(exception); } }
final void work(ForkJoinWorkerThread w) { boolean swept = false; // true on empty scans long c; while (!w.terminate && (int)(c = ctl) >= 0) { int a; // active count if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0) swept = scan(w, a); else if (tryAwaitWork(w, c)) swept = false; } }
private boolean scan(ForkJoinWorkerThread w, int a) { int g = scanGuard; /* * 如果当前只有一个工作线程,将m设置为0,避免没用的扫描。 * 否则获取guard值。 */ int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK; ForkJoinWorkerThread[] ws = workers; if (ws == null || ws.length <= m) // 过期检测 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)) { //窃取成功后,调整queueBase int d = (v.queueBase = b + 1) - v.queueTop; //将牺牲者的stealHint设置为当前工作线程在pool中的下标。 v.stealHint = w.poolIndex; if (d != 0) signalWork(); // 如果牺牲者的任务队列还有任务,继续唤醒(或创建)线程。 w.execTask(t); //执行窃取的任务。 } //计算出下一个随机种子。 r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5); return false; // 返回false,表示不是一个空扫描。 } //前2*m次,随机扫描。 else if (j < 0) { // xorshift r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5; } //后2*m次,顺序扫描。 else ++k; } if (scanGuard != g) // staleness check return false; else { //如果扫描完毕后没找到可窃取的任务,那么从Pool的提交任务队列中取一个任务来执行。 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; // 如果所有的队列(工作线程的任务队列和pool的任务队列)都是空的,返回true。 } }
final void execTask(ForkJoinTask<?> t) { currentSteal = t; for (;;) { if (t != null) //执行任务 t.doExec(); if (queueTop == queueBase) break; //如果当前工作线程的任务队列里没有任务了,退出循环。 //否则,根据模式来获取任务。 //如果Pool中指定为异步模式,这里从当前任务队列的尾部获取任务;否则,从任务队列头部获取任务。 t = locallyFifo ? locallyDeqTask() : popTask(); } ++stealCount; //最后累加窃取任务计数。 currentSteal = null; }看下execTask方法中调用的的ForJoinTask的doExec方法:
final void doExec() { if (status >= 0) { boolean completed; try { //调用exec方法执行任务 completed = exec(); } catch (Throwable rex) { //设置异常完成结果 setExceptionalCompletion(rex); return; } if (completed) setCompletion(NORMAL); // 设置正常完成结果 } }ForJoinTask中的exec方法是一个抽象方法,具体执行逻辑交给子类去实现,我们前面看到的适配类AdaptedRunnable和AdaptedCallable里面,会在exec里面分别调用runnable.run()和callable.call()方法;而在ForJoinTask的两个子类RecursiveAction和RecursiveTask里面,exec里面调用的是compute方法:
public abstract class RecursiveAction extends ForkJoinTask<Void> { private static final long serialVersionUID = 5232453952276485070L; /** * The main computation performed by this task. */ protected abstract void compute(); public final Void getRawResult() { return null; } protected final void setRawResult(Void mustBeNull) { } /** * Implements execution conventions for RecursiveActions. */ protected final boolean exec() { compute(); return true; } } public abstract class RecursiveTask<V> extends ForkJoinTask<V> { private static final long serialVersionUID = 5232453952276485270L; V result; /** * The main computation performed by this task. */ protected abstract V compute(); public final V getRawResult() { return result; } protected final void setRawResult(V value) { result = value; } /** * Implements execution conventions for RecursiveTask. */ protected final boolean exec() { result = compute(); return true; } }注意ForJoinTask的exec方法有返回值,表示任务是否执行完毕。doExec方法中会根据这个返回值来设置任务的完成状态,如果任务正常完成,会调用setCompletion(NORMAL):
/** The run status of this task */ volatile int status; // accessed directly by pool and workers private static final int NORMAL = -1; ... private int setCompletion(int completion) { for (int s;;) { if ((s = status) < 0) return s; //尝试将任务状态设置为正常完成。 if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { if (s != 0) //同时唤醒合并当前任务的等待线程。 synchronized (this) { notifyAll(); } return completion; } } }doExec方法中如果执行exec方法发生异常,会调用setExceptionalCompletion方法来设置异常完成状态:
private int setExceptionalCompletion(Throwable ex) { //计算当前对象的原生hashCode。 int h = System.identityHashCode(this); final ReentrantLock lock = exceptionTableLock; lock.lock(); try { //删除异常表中过期的异常。 expungeStaleExceptions(); //获取异常表 ExceptionNode[] t = exceptionTable; //通过当前对象hashCode获取在异常表中的下标。 int i = h & (t.length - 1); //设置异常节点。 for (ExceptionNode e = t[i]; ; e = e.next) { if (e == null) { t[i] = new ExceptionNode(this, ex, t[i]); break; } if (e.get() == this) // already present break; } } finally { lock.unlock(); } return setCompletion(EXCEPTIONAL); }
private static final ExceptionNode[] exceptionTable; private static final ReentrantLock exceptionTableLock; private static final ReferenceQueue<Object> exceptionTableRefQueue; private static final int EXCEPTION_MAP_CAPACITY = 32; static final class ExceptionNode extends WeakReference<ForkJoinTask<?>>{ final Throwable ex; ExceptionNode next; final long thrower; // use id not ref to avoid weak cycles ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) { super(task, exceptionTableRefQueue); this.ex = ex; this.next = next; this.thrower = Thread.currentThread().getId(); } } ... // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long statusOffset; static { exceptionTableLock = new ReentrantLock(); exceptionTableRefQueue = new ReferenceQueue<Object>(); exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY]; try { UNSAFE = sun.misc.Unsafe.getUnsafe(); statusOffset = UNSAFE.objectFieldOffset (ForkJoinTask.class.getDeclaredField("status")); } catch (Exception e) { throw new Error(e); } }
继续我们的流程,执行完doExec,方法返回到execTask,接下来由于当前工作线程自身的任务队列中并没有任务,所以queueTop == queueBase成立,execTask方法退出到scan方法,scan方法返回false到ForkJoinPool的work方法,进行下一次扫描(scan),由于工作线程本身的任务队列和Pool的任务队列都为空,所以下一次扫描一定是个空扫描,然后程序会走到work方法的tryAwaitWork分支,看下tryAwaitWork方法:
private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) { int v = w.eventCount; //w的nextWait保存的是等待之前Pool的控制信息。 w.nextWait = (int)c; //这里是将当前线程的ID信息(下标取反)记录到Pool控制信息上 //同时将控制信息上的活动工作线程计数减1。 long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK)); if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) { long d = ctl; // 如果和另外的一个窃取线程竞争并失败,这里返回true,work方法中会继续扫描。 return (int)d != (int)c && ((d - c) & AC_MASK) >= 0L; } for (int sc = w.stealCount; sc != 0;) { //将工作线程上的stealCount原子累加到Pool的stealCount上面。 long s = stealCount; if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc)) sc = w.stealCount = 0; else if (w.eventCount != v) return true; //如果eventCount发生变化,重试。 } if ((!shutdown || !tryTerminate(false)) && (int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 && blockedCount == 0 && quiescerCount == 0) //如果满足上面的条件,说明当前Pool休眠了,需要调用下idleAwaitWork进行处理。 //上面的条件是:Pool未关闭 且 有工作线程 且 活动的工作线程数量等于cpu核心数量 //且没有工作线程在合并过程中阻塞 且 没有工作线程休眠。 idleAwaitWork(w, nc, c, v); // quiescent for (boolean rescanned = false;;) { if (w.eventCount != v) return true; //如果eventCount发生变化,重试。 if (!rescanned) { int g = scanGuard, m = g & SMASK; ForkJoinWorkerThread[] ws = workers; if (ws != null && m < ws.length) { rescanned = true; //这里再重新扫描一下,如果从其他工作线程任务队列里找到任务,尝试唤醒等待的工作线程。 for (int i = 0; i <= m; ++i) { ForkJoinWorkerThread u = ws[i]; if (u != null) { if (u.queueBase != u.queueTop && !tryReleaseWaiter()) rescanned = false; // 发生竞争,再次扫描。 if (w.eventCount != v) return true; } } } if (scanGuard != g || // scanGuard发生变化 (queueBase != queueTop && !tryReleaseWaiter())) //或者从Pool任务队列中找到任务 rescanned = false; //再次扫描 if (!rescanned) Thread.yield(); // 出让cpu,减少竞争。 else Thread.interrupted(); // park前清除中断标记。 } else { w.parked = true; // 设置park标记 if (w.eventCount != v) { //再检测一下。 w.parked = false; return true; } LockSupport.park(this); rescanned = w.parked = false; } } }
- 如果按照我们的流程,到这儿就结束了,工作线程已经执行了我们提交的任务,然后阻塞等待了。但如果当前Pool正好处于休眠状态了,看看会怎么样,继续看下上面方法中调用的idleAwaitWork方法:
private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl, long prevCtl, int v) { if (w.eventCount == v) { if (shutdown) tryTerminate(false); //如果关闭方法已经被调用,那么调用tryTerminate ForkJoinTask.helpExpungeStaleExceptions(); // 清理一下异常表中weak key while (ctl == currentCtl) { long startTime = System.nanoTime(); w.parked = true; if (w.eventCount == v) LockSupport.parkNanos(this, SHRINK_RATE); //阻塞给定时间(4秒) w.parked = false; if (w.eventCount != v) break; else if (System.nanoTime() - startTime < SHRINK_RATE - (SHRINK_RATE / 10)) Thread.interrupted(); // 如果发生伪唤醒,清除中断标志。 //恢复之前的ctl,如果ctl一直没发生变化,会成功。 else if (UNSAFE.compareAndSwapLong(this, ctlOffset, currentCtl, prevCtl)) { //结束工作线程 w.terminate = true; // 设置结束标志。 w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK; //设置w的eventCount。 break; } } } }
可见,idleAwaitWork方法中开始会检测一下Pool是否正在关闭,是的话要调用tryTerminate;否则会先将工作线程w阻塞一段时间(4s),如果超过了这个时间,Pool的控制信息还没发生变化(说明Pool还是休眠状态),那么就需要将w结束掉,会设置w的结束标记为true,同时设置w的eventCount,然后退出到tryAwaitWork方法,tryAwaitWork方法中检测到w的eventCount发生变化,会退出到work方法,work方法中检测到w的结束标记为true,主循环回退出,工作线程w就要结束了,结束时会调用w的onTermination方法(上面提到过):
protected void onTermination(Throwable exception) { try { terminate = true; cancelTasks(); pool.deregisterWorker(this, exception); } catch (Throwable ex) { // Shouldn't ever happen if (exception == null) // but if so, at least rethrown exception = ex; } finally { if (exception != null) UNSAFE.throwException(exception); } }
先看下取消任务:
final void cancelTasks() { ForkJoinTask<?> cj = currentJoin; if (cj != null && cj.status >= 0) cj.cancelIgnoringExceptions(); //取消正在合并的任务 ForkJoinTask<?> cs = currentSteal; if (cs != null && cs.status >= 0) cs.cancelIgnoringExceptions(); //取消窃取的任务 while (queueBase != queueTop) { ForkJoinTask<?> t = deqTask(); //取消工作线程任务队列中的所有任务。 if (t != null) t.cancelIgnoringExceptions(); } }
看下这个取消方法cancelIgnoringExceptions:
private static final int CANCELLED = -2; ... final void cancelIgnoringExceptions() { try { cancel(false); } catch (Throwable ignore) { } } public boolean cancel(boolean mayInterruptIfRunning) { return setCompletion(CANCELLED) == CANCELLED; } private int setCompletion(int completion) { for (int s;;) { if ((s = status) < 0) return s; if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { if (s != 0) synchronized (this) { notifyAll(); } return completion; } } }
再看下ForkJoinWorkerThread从Pool中注销自己的代码:
final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) { int idx = w.poolIndex; int sc = w.stealCount; int steps = 0; // Remove from array, adjust worker counts and collect steal count. // We can intermix failed removes or adjusts with steal updates do { long s, c; int g; if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 && UNSAFE.compareAndSwapInt(this, scanGuardOffset, g, g |= SG_UNIT)) { ForkJoinWorkerThread[] ws = workers; if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w) ws[idx] = null; // verify nextWorkerIndex = idx; scanGuard = g + SG_UNIT; steps = 1; } if (steps == 1 && UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl, (((c - AC_UNIT) & AC_MASK) | ((c - TC_UNIT) & TC_MASK) | (c & ~(AC_MASK|TC_MASK))))) steps = 2; if (sc != 0 && UNSAFE.compareAndSwapLong(this, stealCountOffset, s = stealCount, s + sc)) sc = 0; } while (steps != 2 || sc != 0); if (!tryTerminate(false)) { if (ex != null) // possibly replace if died abnormally signalWork(); else tryReleaseWaiter(); } }
deregisterWorker在完成注销线程工作后,还有可能会唤醒其他等待线程,首先会调用一下tryTerminate(false):
private boolean tryTerminate(boolean now) { long c; while (((c = ctl) & STOP_BIT) == 0) { if (!now) { if ((int)(c >> AC_SHIFT) != -parallelism) return false; if (!shutdown || blockedCount != 0 || quiescerCount != 0 || queueBase != queueTop) { if (ctl == c) // staleness check return false; continue; } } if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT)) startTerminating(); } if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers final ReentrantLock lock = this.submissionLock; lock.lock(); try { termination.signalAll(); } finally { lock.unlock(); } } return true; }
再看下这个startTerminating方法:
private void startTerminating() { //取消Pool提交任务队列中的任务。 cancelSubmissions(); for (int pass = 0; pass < 3; ++pass) { ForkJoinWorkerThread[] ws = workers; if (ws != null) { for (ForkJoinWorkerThread w : ws) { if (w != null) { //结束工作线程。 w.terminate = true; if (pass > 0) { //取消工作线程中任务队列的任务。 w.cancelTasks(); if (pass > 1 && !w.isInterrupted()) { try { //中断工作线程。 w.interrupt(); } catch (SecurityException ignore) { } } } } } //结束等待的工作线程。 terminateWaiters(); } } }
startTerminating中第1步会调用cancelSubmissions方法:
private void cancelSubmissions() { while (queueBase != queueTop) { ForkJoinTask<?> task = pollSubmission(); if (task != null) { try { task.cancel(false); } catch (Throwable ignore) { } } } } protected ForkJoinTask<?> pollSubmission() { ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i; while ((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; return t; } } return null; }
startTerminating中第5步会调用terminateWaiters方法:
private void terminateWaiters() { ForkJoinWorkerThread[] ws = workers; if (ws != null) { ForkJoinWorkerThread w; long c; int i, e; int n = ws.length; while ((i = ~(e = (int)(c = ctl)) & SMASK) < n && (w = ws[i]) != null && w.eventCount == (e & E_MASK)) { if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, (long)(w.nextWait & E_MASK) | ((c + AC_UNIT) & AC_MASK) | (c & (TC_MASK|STOP_BIT)))) { w.terminate = true; w.eventCount = e + EC_UNIT; if (w.parked) UNSAFE.unpark(w); } } } }
好吧,回到deregisterWorker方法,假设当前Pool还在运行,那么tryTerminate(false)返回false,就会执行接下来的语句:
if (!tryTerminate(false)) { if (ex != null) // possibly replace if died abnormally signalWork(); else tryReleaseWaiter(); }
如果有异常发生,会调用signalWork方法来唤醒或者创建一个工作线程;否则调用tryReleaseWaiter方法来尝试唤醒一个等待工作线程:
private boolean tryReleaseWaiter() { long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws; if ((e = (int)(c = ctl)) > 0 && //如果有等待线程 (int)(c >> AC_SHIFT) < 0 && //且当前活动线程数小于CPU核数 (ws = workers) != null && //检测工作线程数组合法性 (i = ~e & SMASK) < ws.length && //检测控制信息中等待的工作线程的ID信息的合法性。 (w = ws[i]) != null) { //检测工作线程的合法性。 long nc = ((long)(w.nextWait & E_MASK) | ((c + AC_UNIT) & (AC_MASK|TC_MASK))); //尝试调整控制信息,增加活动工作线程计数,将Treiber stack下一个等待线程的ID信息设置到ctl if (w.eventCount != e || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) return false; //如果发生冲突。 w.eventCount = (e + EC_UNIT) & E_MASK; //累加w的eventCount if (w.parked) UNSAFE.unpark(w); //唤醒w。 } return true; }
- OK,让我们在回到ForkJoinWorkerThread的execTask方法(不要晕):
final void execTask(ForkJoinTask<?> t) { currentSteal = t; for (;;) { if (t != null) t.doExec(); if (queueTop == queueBase) break; t = locallyFifo ? locallyDeqTask() : popTask(); } ++stealCount; currentSteal = null; }
如果Pool不是异步模式(locallyFifo为false),那么会执行popTask方法:
private ForkJoinTask<?> popTask() { int m; ForkJoinTask<?>[] q = queue; if (q != null && (m = q.length - 1) >= 0) { for (int s; (s = queueTop) != queueBase;) { int i = m & --s; long u = (i << ASHIFT) + ABASE; // raw offset ForkJoinTask<?> t = q[i]; if (t == null) // lost to stealer break; if (UNSAFE.compareAndSwapObject(q, u, t, null)) { queueTop = s; // or putOrderedInt return t; } } } return null; }
如果Pool是异步模式(locallyFifo为true),那么会执行locallyDeqTask方法:
final ForkJoinTask<?> locallyDeqTask() { ForkJoinTask<?> t; int m, b, i; ForkJoinTask<?>[] q = queue; if (q != null && (m = q.length - 1) >= 0) { while (queueTop != (b = queueBase)) { if ((t = q[i = m & b]) != null && queueBase == b && UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null)) { queueBase = b + 1; return t; } } } return null; }
- 简单总结一下ForkJoinPool中的工作线程的工作流程:
本篇虽然是通过一个非ForkJoin任务的执行过程来分析代码,但已经包含ForkJoinPool运行过程的大部分流程。下篇会再次通过一个ForkJoin任务的流程来重点分析下Fork/Join过程中涉及到的源码。