--- jsr166/src/jsr166y/ForkJoinPool.java 2009/08/03 00:53:15 1.40 +++ jsr166/src/jsr166y/ForkJoinPool.java 2009/12/04 12:09:46 1.50 @@ -23,35 +23,37 @@ import java.util.concurrent.atomic.Atomi * An {@link ExecutorService} for running {@link ForkJoinTask}s. * A {@code ForkJoinPool} provides the entry point for submissions * from non-{@code ForkJoinTask}s, as well as management and - * monitoring operations. Normally a single {@code ForkJoinPool} is - * used for a large number of submitted tasks. Otherwise, use would - * not usually outweigh the construction and bookkeeping overhead of - * creating a large set of threads. + * monitoring operations. * - *

{@code ForkJoinPool}s differ from other kinds of {@link - * Executor}s mainly in that they provide work-stealing: all - * threads in the pool attempt to find and execute subtasks created by - * other active tasks (eventually blocking if none exist). This makes - * them efficient when most tasks spawn other subtasks (as do most - * {@code ForkJoinTask}s), as well as the mixed execution of some - * plain {@code Runnable}- or {@code Callable}- based activities along - * with {@code ForkJoinTask}s. When setting {@linkplain #setAsyncMode - * async mode}, a {@code ForkJoinPool} may also be appropriate for use - * with fine-grained tasks that are never joined. Otherwise, other - * {@code ExecutorService} implementations are typically more - * appropriate choices. + *

A {@code ForkJoinPool} differs from other kinds of {@link + * ExecutorService} mainly by virtue of employing + * work-stealing: all threads in the pool attempt to find and + * execute subtasks created by other active tasks (eventually blocking + * waiting for work if none exist). This enables efficient processing + * when most tasks spawn other subtasks (as do most {@code + * ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed + * execution of some plain {@code Runnable}- or {@code Callable}- + * based activities along with {@code ForkJoinTask}s. When setting + * {@linkplain #setAsyncMode async mode}, a {@code ForkJoinPool} may + * also be appropriate for use with fine-grained tasks of any form + * that are never joined. Otherwise, other {@code ExecutorService} + * implementations are typically more appropriate choices. * - *

A {@code ForkJoinPool} may be constructed with a given - * parallelism level (target pool size), which it attempts to maintain - * by dynamically adding, suspending, or resuming threads, even if - * some tasks are waiting to join others. However, no such adjustments + *

A {@code ForkJoinPool} is constructed with a given target + * parallelism level; by default, equal to the number of available + * processors. Unless configured otherwise via {@link + * #setMaintainsParallelism}, the pool attempts to maintain this + * number of active (or available) threads by dynamically adding, + * suspending, or resuming internal worker threads, even if some tasks + * are stalled waiting to join others. However, no such adjustments * are performed in the face of blocked IO or other unmanaged * synchronization. The nested {@link ManagedBlocker} interface * enables extension of the kinds of synchronization accommodated. * The target parallelism level may also be changed dynamically - * ({@link #setParallelism}) and thread construction can be limited - * using methods {@link #setMaximumPoolSize} and/or {@link - * #setMaintainsParallelism}. + * ({@link #setParallelism}). The total number of threads may be + * limited using method {@link #setMaximumPoolSize}, in which case it + * may become possible for the activities of a pool to stall due to + * the lack of available threads to process new tasks. * *

In addition to execution and lifecycle control methods, this * class provides status check methods (for example @@ -60,11 +62,32 @@ import java.util.concurrent.atomic.Atomi * {@link #toString} returns indications of pool state in a * convenient form for informal monitoring. * + *

Sample Usage. Normally a single {@code ForkJoinPool} is + * used for all parallel task execution in a program or subsystem. + * Otherwise, use would not usually outweigh the construction and + * bookkeeping overhead of creating a large set of threads. For + * example, a common pool could be used for the {@code SortTasks} + * illustrated in {@link RecursiveAction}. Because {@code + * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon + * daemon} mode, there is typically no need to explicitly {@link + * #shutdown} such a pool upon program exit. + * + *

+ * static final ForkJoinPool mainPool = new ForkJoinPool();
+ * ...
+ * public void sort(long[] array) {
+ *   mainPool.invoke(new SortTask(array, 0, array.length));
+ * }
+ * 
+ * *

Implementation notes: This implementation restricts the * maximum number of running threads to 32767. Attempts to create - * pools with greater than the maximum result in + * pools with greater than the maximum number result in * {@code IllegalArgumentException}. * + *

This implementation rejects submitted tasks (that is, by throwing + * {@link RejectedExecutionException}) only when the pool is shut down. + * * @since 1.7 * @author Doug Lea */ @@ -92,7 +115,7 @@ public class ForkJoinPool extends Abstra * Returns a new worker thread operating in the given pool. * * @param pool the pool this thread works in - * @throws NullPointerException if pool is null + * @throws NullPointerException if the pool is null */ public ForkJoinWorkerThread newThread(ForkJoinPool pool); } @@ -343,9 +366,9 @@ public class ForkJoinPool extends Abstra // Constructors /** - * Creates a ForkJoinPool with a pool size equal to the number of - * processors available on the system, using the default - * ForkJoinWorkerThreadFactory. + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. * * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads @@ -358,12 +381,13 @@ public class ForkJoinPool extends Abstra } /** - * Creates a ForkJoinPool with the indicated parallelism level - * threads and using the default ForkJoinWorkerThreadFactory. + * Creates a {@code ForkJoinPool} with the indicated parallelism + * level and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. * - * @param parallelism the number of worker threads + * @param parallelism the parallelism level * @throws IllegalArgumentException if parallelism less than or - * equal to zero + * equal to zero, or greater than implementation limit * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link @@ -374,12 +398,12 @@ public class ForkJoinPool extends Abstra } /** - * Creates a ForkJoinPool with parallelism equal to the number of - * processors available on the system and using the given - * ForkJoinWorkerThreadFactory. + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the given + * thread factory. * * @param factory the factory for creating new threads - * @throws NullPointerException if factory is null + * @throws NullPointerException if the factory is null * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link @@ -390,13 +414,14 @@ public class ForkJoinPool extends Abstra } /** - * Creates a ForkJoinPool with the given parallelism and factory. + * Creates a {@code ForkJoinPool} with the given parallelism and + * thread factory. * - * @param parallelism the targeted number of worker threads + * @param parallelism the parallelism level * @param factory the factory for creating new threads * @throws IllegalArgumentException if parallelism less than or - * equal to zero, or greater than implementation limit - * @throws NullPointerException if factory is null + * equal to zero, or greater than implementation limit + * @throws NullPointerException if the factory is null * @throws SecurityException if a security manager exists and * the caller is not permitted to modify threads * because it does not hold {@link @@ -424,7 +449,7 @@ public class ForkJoinPool extends Abstra * Creates a new worker thread using factory. * * @param index the index to assign worker - * @return new worker, or null of factory failed + * @return new worker, or null if factory failed */ private ForkJoinWorkerThread createWorker(int index) { Thread.UncaughtExceptionHandler h = ueh; @@ -445,8 +470,16 @@ public class ForkJoinPool extends Abstra * Currently requires size to be a power of two. */ private static int arraySizeFor(int poolSize) { - return (poolSize <= 1) ? 1 : - (1 << (32 - Integer.numberOfLeadingZeros(poolSize-1))); + if (poolSize <= 1) + return 1; + // See Hackers Delight, sec 3.2 + int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1); + c |= c >>> 1; + c |= c >>> 2; + c |= c >>> 4; + c |= c >>> 8; + c |= c >>> 16; + return c + 1; } /** @@ -493,14 +526,16 @@ public class ForkJoinPool extends Abstra ws = workers; if (ws == null) { int ps = parallelism; + updateWorkerCount(ps); ws = ensureWorkerArrayCapacity(ps); for (int i = 0; i < ps; ++i) { ForkJoinWorkerThread w = createWorker(i); if (w != null) { ws[i] = w; w.start(); - updateWorkerCount(1); } + else + updateWorkerCount(-1); } } } finally { @@ -564,8 +599,9 @@ public class ForkJoinPool extends Abstra * * @param task the task * @return the task's result - * @throws NullPointerException if task is null - * @throws RejectedExecutionException if pool is shut down + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution */ public T invoke(ForkJoinTask task) { doSubmit(task); @@ -576,8 +612,9 @@ public class ForkJoinPool extends Abstra * Arranges for (asynchronous) execution of the given task. * * @param task the task - * @throws NullPointerException if task is null - * @throws RejectedExecutionException if pool is shut down + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution */ public void execute(ForkJoinTask task) { doSubmit(task); @@ -585,6 +622,11 @@ public class ForkJoinPool extends Abstra // AbstractExecutorService methods + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ public void execute(Runnable task) { ForkJoinTask job; if (task instanceof ForkJoinTask) // avoid re-wrap @@ -594,18 +636,33 @@ public class ForkJoinPool extends Abstra doSubmit(job); } + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ public ForkJoinTask submit(Callable task) { ForkJoinTask job = ForkJoinTask.adapt(task); doSubmit(job); return job; } + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ public ForkJoinTask submit(Runnable task, T result) { ForkJoinTask job = ForkJoinTask.adapt(task, result); doSubmit(job); return job; } + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ public ForkJoinTask submit(Runnable task) { ForkJoinTask job; if (task instanceof ForkJoinTask) // avoid re-wrap @@ -621,9 +678,9 @@ public class ForkJoinPool extends Abstra * * @param task the task to submit * @return the task + * @throws NullPointerException if the task is null * @throws RejectedExecutionException if the task cannot be * scheduled for execution - * @throws NullPointerException if the task is null */ public ForkJoinTask submit(ForkJoinTask task) { doSubmit(task); @@ -631,6 +688,10 @@ public class ForkJoinPool extends Abstra } + /** + * @throws NullPointerException {@inheritDoc} + * @throws RejectedExecutionException {@inheritDoc} + */ public List> invokeAll(Collection> tasks) { ArrayList> forkJoinTasks = new ArrayList>(tasks.size()); @@ -737,13 +798,15 @@ public class ForkJoinPool extends Abstra final ReentrantLock lock = this.workerLock; lock.lock(); try { - if (!isTerminating()) { + if (isProcessingTasks()) { int p = this.parallelism; this.parallelism = parallelism; - if (parallelism > p) - createAndStartAddedWorkers(); - else - trimSpares(); + if (workers != null) { + if (parallelism > p) + createAndStartAddedWorkers(); + else + trimSpares(); + } } } finally { lock.unlock(); @@ -752,9 +815,9 @@ public class ForkJoinPool extends Abstra } /** - * Returns the targeted number of worker threads in this pool. + * Returns the targeted parallelism level of this pool. * - * @return the targeted number of worker threads in this pool + * @return the targeted parallelism level of this pool */ public int getParallelism() { return parallelism; @@ -774,7 +837,9 @@ public class ForkJoinPool extends Abstra /** * Returns the maximum number of threads allowed to exist in the - * pool, even if there are insufficient unblocked running threads. + * pool. Unless set using {@link #setMaximumPoolSize}, the + * maximum is an implementation-defined value designed only to + * prevent runaway growth. * * @return the maximum */ @@ -784,9 +849,10 @@ public class ForkJoinPool extends Abstra /** * Sets the maximum number of threads allowed to exist in the - * pool, even if there are insufficient unblocked running threads. - * Setting this value has no effect on current pool size. It - * controls construction of new threads. + * pool. The given value should normally be greater than or equal + * to the {@link #getParallelism parallelism} level. Setting this + * value has no effect on current pool size. It controls + * construction of new threads. * * @throws IllegalArgumentException if negative or greater than * internal implementation limit @@ -991,8 +1057,8 @@ public class ForkJoinPool extends Abstra * Removes all available unexecuted submitted and forked tasks * from scheduling queues and adds them to the given collection, * without altering their execution status. These may include - * artificially generated or wrapped tasks. This method is designed - * to be invoked only when the pool is known to be + * artificially generated or wrapped tasks. This method is + * designed to be invoked only when the pool is known to be * quiescent. Invocations at other times may not remove all * tasks. A failure encountered while attempting to add elements * to collection {@code c} may result in elements being in @@ -1044,7 +1110,7 @@ public class ForkJoinPool extends Abstra } private static String runStateToString(int rs) { - switch(rs) { + switch (rs) { case RUNNING: return "Running"; case SHUTDOWN: return "Shutting down"; case TERMINATING: return "Terminating"; @@ -1089,14 +1155,14 @@ public class ForkJoinPool extends Abstra } /** - * Attempts to stop all actively executing tasks, and cancels all - * waiting tasks. Tasks that are in the process of being - * submitted or executed concurrently during the course of this - * method may or may not be rejected. Unlike some other executors, - * this method cancels rather than collects non-executed tasks - * upon termination, so always returns an empty list. However, you - * can use method {@link #drainTasksTo} before invoking this - * method to transfer unexecuted tasks to another collection. + * Attempts to cancel and/or stop all tasks, and reject all + * subsequently submitted tasks. Tasks that are in the process of + * being submitted or executed concurrently during the course of + * this method may or may not be rejected. This method cancels + * both existing and unexecuted tasks, in order to permit + * termination in the presence of task dependencies. So the method + * always returns an empty list (unlike the case for some other + * Executors). * * @return an empty list * @throws SecurityException if a security manager exists and @@ -1121,12 +1187,16 @@ public class ForkJoinPool extends Abstra /** * Returns {@code true} if the process of termination has - * commenced but possibly not yet completed. + * commenced but not yet completed. This method may be useful for + * debugging. A return of {@code true} reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, causing this executor not + * to properly terminate. * - * @return {@code true} if terminating + * @return {@code true} if terminating but not yet terminated */ public boolean isTerminating() { - return runStateOf(runControl) >= TERMINATING; + return runStateOf(runControl) == TERMINATING; } /** @@ -1139,6 +1209,14 @@ public class ForkJoinPool extends Abstra } /** + * Returns true if pool is not terminating or terminated. + * Used internally to suppress execution when terminating. + */ + final boolean isProcessingTasks() { + return runStateOf(runControl) < TERMINATING; + } + + /** * Blocks until all tasks have completed execution after a shutdown * request, or the timeout occurs, or the current thread is * interrupted, whichever happens first. @@ -1192,7 +1270,7 @@ public class ForkJoinPool extends Abstra transitionRunStateTo(TERMINATED); termination.signalAll(); } - else if (!isTerminating()) { + else if (isProcessingTasks()) { tryShrinkWorkerArray(); tryResumeSpare(true); // allow replacement } @@ -1302,7 +1380,6 @@ public class ForkJoinPool extends Abstra } } - /* * Nodes for event barrier to manage idle threads. Queue nodes * are basic Treiber stack nodes, also used for spare stack. @@ -1326,15 +1403,14 @@ public class ForkJoinPool extends Abstra * handling: Method signalWork returns without advancing count if * the queue appears to be empty. This would ordinarily result in * races causing some queued waiters not to be woken up. To avoid - * this, the first worker enqueued in method sync (see - * syncIsReleasable) rescans for tasks after being enqueued, and - * helps signal if any are found. This works well because the - * worker has nothing better to do, and so might as well help - * alleviate the overhead and contention on the threads actually - * doing work. Also, since event counts increments on task - * availability exist to maintain liveness (rather than to force - * refreshes etc), it is OK for callers to exit early if - * contending with another signaller. + * this, the first worker enqueued in method sync rescans for + * tasks after being enqueued, and helps signal if any are + * found. This works well because the worker has nothing better to + * do, and so might as well help alleviate the overhead and + * contention on the threads actually doing work. Also, since + * event counts increments on task availability exist to maintain + * liveness (rather than to force refreshes etc), it is OK for + * callers to exit early if contending with another signaller. */ static final class WaitQueueNode { WaitQueueNode next; // only written before enqueued @@ -1347,7 +1423,7 @@ public class ForkJoinPool extends Abstra } /** - * Wakes up waiter, returning false if known to already + * Wakes up waiter, returning false if known to already be awake */ boolean signal() { ForkJoinWorkerThread t = thread; @@ -1357,34 +1433,14 @@ public class ForkJoinPool extends Abstra LockSupport.unpark(t); return true; } - - /** - * Awaits release on sync. - */ - void awaitSyncRelease(ForkJoinPool p) { - while (thread != null && !p.syncIsReleasable(this)) - LockSupport.park(this); - } - - /** - * Awaits resumption as spare. - */ - void awaitSpareRelease() { - while (thread != null) { - if (!Thread.interrupted()) - LockSupport.park(this); - } - } } /** * Ensures that no thread is waiting for count to advance from the * current value of eventCount read on entry to this method, by * releasing waiting threads if necessary. - * - * @return the count */ - final long ensureSync() { + final void ensureSync() { long c = eventCount; WaitQueueNode q; while ((q = syncStack) != null && q.count < c) { @@ -1395,7 +1451,6 @@ public class ForkJoinPool extends Abstra break; } } - return c; } /** @@ -1410,17 +1465,18 @@ public class ForkJoinPool extends Abstra /** * Signals threads waiting to poll a task. Because method sync * rechecks availability, it is OK to only proceed if queue - * appears to be non-empty, and OK to skip under contention to - * increment count (since some other thread succeeded). + * appears to be non-empty, and OK if CAS to increment count + * fails (since some other thread succeeded). */ final void signalWork() { - long c; - WaitQueueNode q; - if (syncStack != null && - casEventCount(c = eventCount, c+1) && - (((q = syncStack) != null && q.count <= c) && - (!casBarrierStack(q, q.next) || !q.signal()))) - ensureSync(); + if (syncStack != null) { + long c; + casEventCount(c = eventCount, c+1); + WaitQueueNode q = syncStack; + if (q != null && q.count <= c && + (!casBarrierStack(q, q.next) || !q.signal())) + ensureSync(); + } } /** @@ -1433,53 +1489,38 @@ public class ForkJoinPool extends Abstra final void sync(ForkJoinWorkerThread w) { updateStealCount(w); // Transfer w's count while it is idle - while (!w.isShutdown() && !isTerminating() && !suspendIfSpare(w)) { + if (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) { long prev = w.lastEventCount; WaitQueueNode node = null; WaitQueueNode h; + boolean helpSignal = false; while (eventCount == prev && ((h = syncStack) == null || h.count == prev)) { if (node == null) node = new WaitQueueNode(prev, w); if (casBarrierStack(node.next = h, node)) { - node.awaitSyncRelease(this); + if (!Thread.interrupted() && node.thread != null && + eventCount == prev) { + if (h == null && // cover signalWork race + ForkJoinWorkerThread.hasQueuedTasks(workers)) + helpSignal = true; + else + LockSupport.park(this); + } + if (node.thread != null) + node.thread = null; break; } } - long ec = ensureSync(); - if (ec != prev) { + long ec = eventCount; + if (ec != prev) w.lastEventCount = ec; - break; - } + else if (helpSignal) + casEventCount(ec, ec + 1); + ensureSync(); } } - /** - * Returns {@code true} if worker waiting on sync can proceed: - * - on signal (thread == null) - * - on event count advance (winning race to notify vs signaller) - * - on interrupt - * - if the first queued node, we find work available - * If node was not signalled and event count not advanced on exit, - * then we also help advance event count. - * - * @return {@code true} if node can be released - */ - final boolean syncIsReleasable(WaitQueueNode node) { - long prev = node.count; - if (!Thread.interrupted() && node.thread != null && - (node.next != null || - !ForkJoinWorkerThread.hasQueuedTasks(workers)) && - eventCount == prev) - return false; - if (node.thread != null) { - node.thread = null; - long ec = eventCount; - if (prev <= ec) // help signal - casEventCount(ec, ec+1); - } - return true; - } /** * Returns {@code true} if a new sync event occurred since last @@ -1487,11 +1528,11 @@ public class ForkJoinPool extends Abstra */ final boolean hasNewSyncEvent(ForkJoinWorkerThread w) { long lc = w.lastEventCount; - long ec = ensureSync(); - if (ec == lc) - return false; - w.lastEventCount = ec; - return true; + long ec = eventCount; + if (lc != ec) + w.lastEventCount = ec; + ensureSync(); + return lc != ec || lc != eventCount; } // Parallelism maintenance @@ -1533,7 +1574,6 @@ public class ForkJoinPool extends Abstra while (spareStack == null || !tryResumeSpare(dec)) { int counts = workerCounts; if (dec || (dec = casWorkerCounts(counts, --counts))) { - // CAS cheat if (!needSpare(counts, maintainParallelism)) break; if (joinMe.status < 0) @@ -1638,7 +1678,7 @@ public class ForkJoinPool extends Abstra for (k = 0; k < len && ws[k] != null; ++k) ; } - if (k < len && !isTerminating() && (w = createWorker(k)) != null) { + if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) { ws[k] = w; w.start(); } @@ -1658,19 +1698,25 @@ public class ForkJoinPool extends Abstra */ private boolean suspendIfSpare(ForkJoinWorkerThread w) { WaitQueueNode node = null; - int s; - while (parallelism < runningCountOf(s = workerCounts)) { + for (;;) { + int p = parallelism; + int s = workerCounts; + int r = runningCountOf(s); + int t = totalCountOf(s); + // use t as bound if r transiently out of sync + if (t <= p || r <= p) + return false; // not a spare if (node == null) node = new WaitQueueNode(0, w); - if (casWorkerCounts(s, s-1)) { // representation-dependent - // push onto stack - do {} while (!casSpareStack(node.next = spareStack, node)); - // block until released by resumeSpare - node.awaitSpareRelease(); - return true; - } + if (casWorkerCounts(s, workerCountsFor(t, r - 1))) + break; } - return false; + // push onto stack + do {} while (!casSpareStack(node.next = spareStack, node)); + // block until released by resumeSpare + while (!Thread.interrupted() && node.thread != null) + LockSupport.park(this); + return true; } /**