You need to sign in or sign up before continuing.
提交 cc310075 编写于 作者: D dl

6978087: jsr166y Updates

Summary: Simplify the ForkJoinPool API, reworking some of the internals
Reviewed-by: martin, dholmes, chegar
上级 174db961
...@@ -40,16 +40,23 @@ import java.util.Arrays; ...@@ -40,16 +40,23 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.Condition; import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* An {@link ExecutorService} for running {@link ForkJoinTask}s. * An {@link ExecutorService} for running {@link ForkJoinTask}s.
* A {@code ForkJoinPool} provides the entry point for submissions * A {@code ForkJoinPool} provides the entry point for submissions
* from non-{@code ForkJoinTask}s, as well as management and * from non-{@code ForkJoinTask} clients, as well as management and
* monitoring operations. * monitoring operations.
* *
* <p>A {@code ForkJoinPool} differs from other kinds of {@link * <p>A {@code ForkJoinPool} differs from other kinds of {@link
...@@ -58,29 +65,19 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -58,29 +65,19 @@ import java.util.concurrent.atomic.AtomicLong;
* execute subtasks created by other active tasks (eventually blocking * execute subtasks created by other active tasks (eventually blocking
* waiting for work if none exist). This enables efficient processing * waiting for work if none exist). This enables efficient processing
* when most tasks spawn other subtasks (as do most {@code * when most tasks spawn other subtasks (as do most {@code
* ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed * ForkJoinTask}s). When setting <em>asyncMode</em> to true in
* execution of some plain {@code Runnable}- or {@code Callable}- * constructors, {@code ForkJoinPool}s may also be appropriate for use
* based activities along with {@code ForkJoinTask}s. When setting * with event-style tasks that are never joined.
* {@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.
* *
* <p>A {@code ForkJoinPool} is constructed with a given target * <p>A {@code ForkJoinPool} is constructed with a given target
* parallelism level; by default, equal to the number of available * parallelism level; by default, equal to the number of available
* processors. Unless configured otherwise via {@link * processors. The pool attempts to maintain enough active (or
* #setMaintainsParallelism}, the pool attempts to maintain this * available) threads by dynamically adding, suspending, or resuming
* number of active (or available) threads by dynamically adding, * internal worker threads, even if some tasks are stalled waiting to
* suspending, or resuming internal worker threads, even if some tasks * join others. However, no such adjustments are guaranteed in the
* are stalled waiting to join others. However, no such adjustments * face of blocked IO or other unmanaged synchronization. The nested
* are performed in the face of blocked IO or other unmanaged * {@link ManagedBlocker} interface enables extension of the kinds of
* synchronization. The nested {@link ManagedBlocker} interface * synchronization accommodated.
* enables extension of the kinds of synchronization accommodated.
* The target parallelism level may also be changed dynamically
* ({@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.
* *
* <p>In addition to execution and lifecycle control methods, this * <p>In addition to execution and lifecycle control methods, this
* class provides status check methods (for example * class provides status check methods (for example
...@@ -89,6 +86,40 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -89,6 +86,40 @@ import java.util.concurrent.atomic.AtomicLong;
* {@link #toString} returns indications of pool state in a * {@link #toString} returns indications of pool state in a
* convenient form for informal monitoring. * convenient form for informal monitoring.
* *
* <p> As is the case with other ExecutorServices, there are three
* main task execution methods summarized in the following
* table. These are designed to be used by clients not already engaged
* in fork/join computations in the current pool. The main forms of
* these methods accept instances of {@code ForkJoinTask}, but
* overloaded forms also allow mixed execution of plain {@code
* Runnable}- or {@code Callable}- based activities as well. However,
* tasks that are already executing in a pool should normally
* <em>NOT</em> use these pool execution methods, but instead use the
* within-computation forms listed in the table.
*
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <tr>
* <td></td>
* <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
* <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
* </tr>
* <tr>
* <td> <b>Arrange async execution</td>
* <td> {@link #execute(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#fork}</td>
* </tr>
* <tr>
* <td> <b>Await and obtain result</td>
* <td> {@link #invoke(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#invoke}</td>
* </tr>
* <tr>
* <td> <b>Arrange exec and obtain Future</td>
* <td> {@link #submit(ForkJoinTask)}</td>
* <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
* </tr>
* </table>
*
* <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is * <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is
* used for all parallel task execution in a program or subsystem. * used for all parallel task execution in a program or subsystem.
* Otherwise, use would not usually outweigh the construction and * Otherwise, use would not usually outweigh the construction and
...@@ -113,7 +144,8 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -113,7 +144,8 @@ import java.util.concurrent.atomic.AtomicLong;
* {@code IllegalArgumentException}. * {@code IllegalArgumentException}.
* *
* <p>This implementation rejects submitted tasks (that is, by throwing * <p>This implementation rejects submitted tasks (that is, by throwing
* {@link RejectedExecutionException}) only when the pool is shut down. * {@link RejectedExecutionException}) only when the pool is shut down
* or internal resources have been exhausted.
* *
* @since 1.7 * @since 1.7
* @author Doug Lea * @author Doug Lea
...@@ -121,16 +153,247 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -121,16 +153,247 @@ import java.util.concurrent.atomic.AtomicLong;
public class ForkJoinPool extends AbstractExecutorService { public class ForkJoinPool extends AbstractExecutorService {
/* /*
* See the extended comments interspersed below for design, * Implementation Overview
* rationale, and walkthroughs. *
* This class provides the central bookkeeping and control for a
* set of worker threads: Submissions from non-FJ threads enter
* into a submission queue. Workers take these tasks and typically
* split them into subtasks that may be stolen by other workers.
* The main work-stealing mechanics implemented in class
* ForkJoinWorkerThread give first priority to processing tasks
* from their own queues (LIFO or FIFO, depending on mode), then
* to randomized FIFO steals of tasks in other worker queues, and
* lastly to new submissions. These mechanics do not consider
* affinities, loads, cache localities, etc, so rarely provide the
* best possible performance on a given machine, but portably
* provide good throughput by averaging over these factors.
* (Further, even if we did try to use such information, we do not
* usually have a basis for exploiting it. For example, some sets
* of tasks profit from cache affinities, but others are harmed by
* cache pollution effects.)
*
* Beyond work-stealing support and essential bookkeeping, the
* main responsibility of this framework is to take actions when
* one worker is waiting to join a task stolen (or always held by)
* another. Because we are multiplexing many tasks on to a pool
* of workers, we can't just let them block (as in Thread.join).
* We also cannot just reassign the joiner's run-time stack with
* another and replace it later, which would be a form of
* "continuation", that even if possible is not necessarily a good
* idea. Given that the creation costs of most threads on most
* systems mainly surrounds setting up runtime stacks, thread
* creation and switching is usually not much more expensive than
* stack creation and switching, and is more flexible). Instead we
* combine two tactics:
*
* Helping: Arranging for the joiner to execute some task that it
* would be running if the steal had not occurred. Method
* ForkJoinWorkerThread.helpJoinTask tracks joining->stealing
* links to try to find such a task.
*
* Compensating: Unless there are already enough live threads,
* method helpMaintainParallelism() may create or
* re-activate a spare thread to compensate for blocked
* joiners until they unblock.
*
* It is impossible to keep exactly the target (parallelism)
* number of threads running at any given time. Determining
* existence of conservatively safe helping targets, the
* availability of already-created spares, and the apparent need
* to create new spares are all racy and require heuristic
* guidance, so we rely on multiple retries of each. Compensation
* occurs in slow-motion. It is triggered only upon timeouts of
* Object.wait used for joins. This reduces poor decisions that
* would otherwise be made when threads are waiting for others
* that are stalled because of unrelated activities such as
* garbage collection.
*
* The ManagedBlocker extension API can't use helping so relies
* only on compensation in method awaitBlocker.
*
* The main throughput advantages of work-stealing stem from
* decentralized control -- workers mostly steal tasks from each
* other. We do not want to negate this by creating bottlenecks
* implementing other management responsibilities. So we use a
* collection of techniques that avoid, reduce, or cope well with
* contention. These entail several instances of bit-packing into
* CASable fields to maintain only the minimally required
* atomicity. To enable such packing, we restrict maximum
* parallelism to (1<<15)-1 (enabling twice this (to accommodate
* unbalanced increments and decrements) to fit into a 16 bit
* field, which is far in excess of normal operating range. Even
* though updates to some of these bookkeeping fields do sometimes
* contend with each other, they don't normally cache-contend with
* updates to others enough to warrant memory padding or
* isolation. So they are all held as fields of ForkJoinPool
* objects. The main capabilities are as follows:
*
* 1. Creating and removing workers. Workers are recorded in the
* "workers" array. This is an array as opposed to some other data
* structure to support index-based random steals by workers.
* Updates to the array recording new workers and unrecording
* terminated ones are protected from each other by a lock
* (workerLock) but the array is otherwise concurrently readable,
* and accessed directly by workers. To simplify index-based
* operations, the array size is always a power of two, and all
* readers must tolerate null slots. Currently, all worker thread
* creation is on-demand, triggered by task submissions,
* replacement of terminated workers, and/or compensation for
* blocked workers. However, all other support code is set up to
* work with other policies.
*
* To ensure that we do not hold on to worker references that
* would prevent GC, ALL accesses to workers are via indices into
* the workers array (which is one source of some of the unusual
* code constructions here). In essence, the workers array serves
* as a WeakReference mechanism. Thus for example the event queue
* stores worker indices, not worker references. Access to the
* workers in associated methods (for example releaseEventWaiters)
* must both index-check and null-check the IDs. All such accesses
* ignore bad IDs by returning out early from what they are doing,
* since this can only be associated with shutdown, in which case
* it is OK to give up. On termination, we just clobber these
* data structures without trying to use them.
*
* 2. Bookkeeping for dynamically adding and removing workers. We
* aim to approximately maintain the given level of parallelism.
* When some workers are known to be blocked (on joins or via
* ManagedBlocker), we may create or resume others to take their
* place until they unblock (see below). Implementing this
* requires counts of the number of "running" threads (i.e., those
* that are neither blocked nor artificially suspended) as well as
* the total number. These two values are packed into one field,
* "workerCounts" because we need accurate snapshots when deciding
* to create, resume or suspend. Note however that the
* correspondence of these counts to reality is not guaranteed. In
* particular updates for unblocked threads may lag until they
* actually wake up.
*
* 3. Maintaining global run state. The run state of the pool
* consists of a runLevel (SHUTDOWN, TERMINATING, etc) similar to
* those in other Executor implementations, as well as a count of
* "active" workers -- those that are, or soon will be, or
* recently were executing tasks. The runLevel and active count
* are packed together in order to correctly trigger shutdown and
* termination. Without care, active counts can be subject to very
* high contention. We substantially reduce this contention by
* relaxing update rules. A worker must claim active status
* prospectively, by activating if it sees that a submitted or
* stealable task exists (it may find after activating that the
* task no longer exists). It stays active while processing this
* task (if it exists) and any other local subtasks it produces,
* until it cannot find any other tasks. It then tries
* inactivating (see method preStep), but upon update contention
* instead scans for more tasks, later retrying inactivation if it
* doesn't find any.
*
* 4. Managing idle workers waiting for tasks. We cannot let
* workers spin indefinitely scanning for tasks when none are
* available. On the other hand, we must quickly prod them into
* action when new tasks are submitted or generated. We
* park/unpark these idle workers using an event-count scheme.
* Field eventCount is incremented upon events that may enable
* workers that previously could not find a task to now find one:
* Submission of a new task to the pool, or another worker pushing
* a task onto a previously empty queue. (We also use this
* mechanism for configuration and termination actions that
* require wakeups of idle workers). Each worker maintains its
* last known event count, and blocks when a scan for work did not
* find a task AND its lastEventCount matches the current
* eventCount. Waiting idle workers are recorded in a variant of
* Treiber stack headed by field eventWaiters which, when nonzero,
* encodes the thread index and count awaited for by the worker
* thread most recently calling eventSync. This thread in turn has
* a record (field nextEventWaiter) for the next waiting worker.
* In addition to allowing simpler decisions about need for
* wakeup, the event count bits in eventWaiters serve the role of
* tags to avoid ABA errors in Treiber stacks. Upon any wakeup,
* released threads also try to release at most two others. The
* net effect is a tree-like diffusion of signals, where released
* threads (and possibly others) help with unparks. To further
* reduce contention effects a bit, failed CASes to increment
* field eventCount are tolerated without retries in signalWork.
* Conceptually they are merged into the same event, which is OK
* when their only purpose is to enable workers to scan for work.
*
* 5. Managing suspension of extra workers. When a worker notices
* (usually upon timeout of a wait()) that there are too few
* running threads, we may create a new thread to maintain
* parallelism level, or at least avoid starvation. Usually, extra
* threads are needed for only very short periods, yet join
* dependencies are such that we sometimes need them in
* bursts. Rather than create new threads each time this happens,
* we suspend no-longer-needed extra ones as "spares". For most
* purposes, we don't distinguish "extra" spare threads from
* normal "core" threads: On each call to preStep (the only point
* at which we can do this) a worker checks to see if there are
* now too many running workers, and if so, suspends itself.
* Method helpMaintainParallelism looks for suspended threads to
* resume before considering creating a new replacement. The
* spares themselves are encoded on another variant of a Treiber
* Stack, headed at field "spareWaiters". Note that the use of
* spares is intrinsically racy. One thread may become a spare at
* about the same time as another is needlessly being created. We
* counteract this and related slop in part by requiring resumed
* spares to immediately recheck (in preStep) to see whether they
* should re-suspend.
*
* 6. Killing off unneeded workers. A timeout mechanism is used to
* shed unused workers: The oldest (first) event queue waiter uses
* a timed rather than hard wait. When this wait times out without
* a normal wakeup, it tries to shutdown any one (for convenience
* the newest) other spare or event waiter via
* tryShutdownUnusedWorker. This eventually reduces the number of
* worker threads to a minimum of one after a long enough period
* without use.
*
* 7. Deciding when to create new workers. The main dynamic
* control in this class is deciding when to create extra threads
* in method helpMaintainParallelism. We would like to keep
* exactly #parallelism threads running, which is an impossible
* task. We always need to create one when the number of running
* threads would become zero and all workers are busy. Beyond
* this, we must rely on heuristics that work well in the
* presence of transient phenomena such as GC stalls, dynamic
* compilation, and wake-up lags. These transients are extremely
* common -- we are normally trying to fully saturate the CPUs on
* a machine, so almost any activity other than running tasks
* impedes accuracy. Our main defense is to allow parallelism to
* lapse for a while during joins, and use a timeout to see if,
* after the resulting settling, there is still a need for
* additional workers. This also better copes with the fact that
* some of the methods in this class tend to never become compiled
* (but are interpreted), so some components of the entire set of
* controls might execute 100 times faster than others. And
* similarly for cases where the apparent lack of work is just due
* to GC stalls and other transient system activity.
*
* Beware that there is a lot of representation-level coupling
* among classes ForkJoinPool, ForkJoinWorkerThread, and
* ForkJoinTask. For example, direct access to "workers" array by
* workers, and direct access to ForkJoinTask.status by both
* ForkJoinPool and ForkJoinWorkerThread. There is little point
* trying to reduce this, since any associated future changes in
* representations will need to be accompanied by algorithmic
* changes anyway.
*
* Style notes: There are lots of inline assignments (of form
* "while ((local = field) != 0)") which are usually the simplest
* way to ensure the required read orderings (which are sometimes
* critical). Also several occurrences of the unusual "do {}
* while (!cas...)" which is the simplest way to force an update of
* a CAS'ed variable. There are also other coding oddities that
* help some methods perform reasonably even when interpreted (not
* compiled), at the expense of some messy constructions that
* reduce byte code counts.
*
* The order of declarations in this file is: (1) statics (2)
* fields (along with constants used when unpacking some of them)
* (3) internal control methods (4) callbacks and other support
* for ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
* methods (plus a few little helpers).
*/ */
/** Mask for packing and unpacking shorts */
private static final int shortMask = 0xffff;
/** Max pool size -- must be a power of two minus 1 */
private static final int MAX_THREADS = 0x7FFF;
/** /**
* Factory for creating new {@link ForkJoinWorkerThread}s. * Factory for creating new {@link ForkJoinWorkerThread}s.
* A {@code ForkJoinWorkerThreadFactory} must be defined and used * A {@code ForkJoinWorkerThreadFactory} must be defined and used
...@@ -151,14 +414,10 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -151,14 +414,10 @@ public class ForkJoinPool extends AbstractExecutorService {
* Default ForkJoinWorkerThreadFactory implementation; creates a * Default ForkJoinWorkerThreadFactory implementation; creates a
* new ForkJoinWorkerThread. * new ForkJoinWorkerThread.
*/ */
static class DefaultForkJoinWorkerThreadFactory static class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory { implements ForkJoinWorkerThreadFactory {
public ForkJoinWorkerThread newThread(ForkJoinPool pool) { public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
try { return new ForkJoinWorkerThread(pool);
return new ForkJoinWorkerThread(pool);
} catch (OutOfMemoryError oom) {
return null;
}
} }
} }
...@@ -194,508 +453,922 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -194,508 +453,922 @@ public class ForkJoinPool extends AbstractExecutorService {
new AtomicInteger(); new AtomicInteger();
/** /**
* Array holding all worker threads in the pool. Initialized upon * The time to block in a join (see awaitJoin) before checking if
* first use. Array size must be a power of two. Updates and * a new worker should be (re)started to maintain parallelism
* replacements are protected by workerLock, but it is always kept * level. The value should be short enough to maintain global
* in a consistent enough state to be randomly accessed without * responsiveness and progress but long enough to avoid
* locking by workers performing work-stealing. * counterproductive firings during GC stalls or unrelated system
* activity, and to not bog down systems with continual re-firings
* on GCs or legitimately long waits.
*/ */
volatile ForkJoinWorkerThread[] workers; private static final long JOIN_TIMEOUT_MILLIS = 250L; // 4 per second
/** /**
* Lock protecting access to workers. * The wakeup interval (in nanoseconds) for the oldest worker
* waiting for an event to invoke tryShutdownUnusedWorker to
* shrink the number of workers. The exact value does not matter
* too much. It must be short enough to release resources during
* sustained periods of idleness, but not so short that threads
* are continually re-created.
*/ */
private final ReentrantLock workerLock; private static final long SHRINK_RATE_NANOS =
30L * 1000L * 1000L * 1000L; // 2 per minute
/** /**
* Condition for awaitTermination. * Absolute bound for parallelism level. Twice this number plus
* one (i.e., 0xfff) must fit into a 16bit field to enable
* word-packing for some counts and indices.
*/ */
private final Condition termination; private static final int MAX_WORKERS = 0x7fff;
/** /**
* The uncaught exception handler used when any worker * Array holding all worker threads in the pool. Array size must
* abruptly terminates * be a power of two. Updates and replacements are protected by
* workerLock, but the array is always kept in a consistent enough
* state to be randomly accessed without locking by workers
* performing work-stealing, as well as other traversal-based
* methods in this class. All readers must tolerate that some
* array slots may be null.
*/ */
private Thread.UncaughtExceptionHandler ueh; volatile ForkJoinWorkerThread[] workers;
/** /**
* Creation factory for worker threads. * Queue for external submissions.
*/ */
private final ForkJoinWorkerThreadFactory factory; private final LinkedTransferQueue<ForkJoinTask<?>> submissionQueue;
/** /**
* Head of stack of threads that were created to maintain * Lock protecting updates to workers array.
* parallelism when other threads blocked, but have since
* suspended when the parallelism level rose.
*/ */
private volatile WaitQueueNode spareStack; private final ReentrantLock workerLock;
/** /**
* Sum of per-thread steal counts, updated only when threads are * Latch released upon termination.
* idle or terminating.
*/ */
private final AtomicLong stealCount; private final Phaser termination;
/** /**
* Queue for external submissions. * Creation factory for worker threads.
*/ */
private final LinkedTransferQueue<ForkJoinTask<?>> submissionQueue; private final ForkJoinWorkerThreadFactory factory;
/** /**
* Head of Treiber stack for barrier sync. See below for explanation. * Sum of per-thread steal counts, updated only when threads are
* idle or terminating.
*/ */
private volatile WaitQueueNode syncStack; private volatile long stealCount;
/** /**
* The count for event barrier * Encoded record of top of Treiber stack of threads waiting for
* events. The top 32 bits contain the count being waited for. The
* bottom 16 bits contains one plus the pool index of waiting
* worker thread. (Bits 16-31 are unused.)
*/ */
private volatile long eventCount; private volatile long eventWaiters;
/** private static final int EVENT_COUNT_SHIFT = 32;
* Pool number, just for assigning useful names to worker threads private static final long WAITER_ID_MASK = (1L << 16) - 1L;
*/
private final int poolNumber;
/** /**
* The maximum allowed pool size * A counter for events that may wake up worker threads:
* - Submission of a new task to the pool
* - A worker pushing a task on an empty queue
* - termination
*/ */
private volatile int maxPoolSize; private volatile int eventCount;
/** /**
* The desired parallelism level, updated only under workerLock. * Encoded record of top of Treiber stack of spare threads waiting
* for resumption. The top 16 bits contain an arbitrary count to
* avoid ABA effects. The bottom 16bits contains one plus the pool
* index of waiting worker thread.
*/ */
private volatile int parallelism; private volatile int spareWaiters;
private static final int SPARE_COUNT_SHIFT = 16;
private static final int SPARE_ID_MASK = (1 << 16) - 1;
/** /**
* True if use local fifo, not default lifo, for local polling * Lifecycle control. The low word contains the number of workers
* that are (probably) executing tasks. This value is atomically
* incremented before a worker gets a task to run, and decremented
* when a worker has no tasks and cannot find any. Bits 16-18
* contain runLevel value. When all are zero, the pool is
* running. Level transitions are monotonic (running -> shutdown
* -> terminating -> terminated) so each transition adds a bit.
* These are bundled together to ensure consistent read for
* termination checks (i.e., that runLevel is at least SHUTDOWN
* and active threads is zero).
*
* Notes: Most direct CASes are dependent on these bitfield
* positions. Also, this field is non-private to enable direct
* performance-sensitive CASes in ForkJoinWorkerThread.
*/ */
private volatile boolean locallyFifo; volatile int runState;
// Note: The order among run level values matters.
private static final int RUNLEVEL_SHIFT = 16;
private static final int SHUTDOWN = 1 << RUNLEVEL_SHIFT;
private static final int TERMINATING = 1 << (RUNLEVEL_SHIFT + 1);
private static final int TERMINATED = 1 << (RUNLEVEL_SHIFT + 2);
private static final int ACTIVE_COUNT_MASK = (1 << RUNLEVEL_SHIFT) - 1;
/** /**
* Holds number of total (i.e., created and not yet terminated) * Holds number of total (i.e., created and not yet terminated)
* and running (i.e., not blocked on joins or other managed sync) * and running (i.e., not blocked on joins or other managed sync)
* threads, packed into one int to ensure consistent snapshot when * threads, packed together to ensure consistent snapshot when
* making decisions about creating and suspending spare * making decisions about creating and suspending spare
* threads. Updated only by CAS. Note: CASes in * threads. Updated only by CAS. Note that adding a new worker
* updateRunningCount and preJoin assume that running active count * requires incrementing both counts, since workers start off in
* is in low word, so need to be modified if this changes. * running state.
*/ */
private volatile int workerCounts; private volatile int workerCounts;
private static int totalCountOf(int s) { return s >>> 16; } private static final int TOTAL_COUNT_SHIFT = 16;
private static int runningCountOf(int s) { return s & shortMask; } private static final int RUNNING_COUNT_MASK = (1 << TOTAL_COUNT_SHIFT) - 1;
private static int workerCountsFor(int t, int r) { return (t << 16) + r; } private static final int ONE_RUNNING = 1;
private static final int ONE_TOTAL = 1 << TOTAL_COUNT_SHIFT;
/** /**
* Adds delta (which may be negative) to running count. This must * The target parallelism level.
* be called before (with negative arg) and after (with positive) * Accessed directly by ForkJoinWorkerThreads.
* any managed synchronization (i.e., mainly, joins).
*
* @param delta the number to add
*/ */
final void updateRunningCount(int delta) { final int parallelism;
int s;
do {} while (!casWorkerCounts(s = workerCounts, s + delta));
}
/** /**
* Adds delta (which may be negative) to both total and running * True if use local fifo, not default lifo, for local polling
* count. This must be called upon creation and termination of * Read by, and replicated by ForkJoinWorkerThreads
* worker threads.
*
* @param delta the number to add
*/ */
private void updateWorkerCount(int delta) { final boolean locallyFifo;
int d = delta + (delta << 16); // add to both lo and hi parts
int s;
do {} while (!casWorkerCounts(s = workerCounts, s + d));
}
/** /**
* Lifecycle control. High word contains runState, low word * The uncaught exception handler used when any worker abruptly
* contains the number of workers that are (probably) executing * terminates.
* tasks. This value is atomically incremented before a worker
* gets a task to run, and decremented when worker has no tasks
* and cannot find any. These two fields are bundled together to
* support correct termination triggering. Note: activeCount
* CAS'es cheat by assuming active count is in low word, so need
* to be modified if this changes
*/ */
private volatile int runControl; private final Thread.UncaughtExceptionHandler ueh;
// RunState values. Order among values matters /**
private static final int RUNNING = 0; * Pool number, just for assigning useful names to worker threads
private static final int SHUTDOWN = 1; */
private static final int TERMINATING = 2; private final int poolNumber;
private static final int TERMINATED = 3;
private static int runStateOf(int c) { return c >>> 16; } // Utilities for CASing fields. Note that most of these
private static int activeCountOf(int c) { return c & shortMask; } // are usually manually inlined by callers
private static int runControlFor(int r, int a) { return (r << 16) + a; }
/** /**
* Tries incrementing active count; fails on contention. * Increments running count part of workerCounts
* Called by workers before/during executing tasks.
*
* @return true on success
*/ */
final boolean tryIncrementActiveCount() { final void incrementRunningCount() {
int c = runControl; int c;
return casRunControl(c, c+1); do {} while (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
c = workerCounts,
c + ONE_RUNNING));
} }
/** /**
* Tries decrementing active count; fails on contention. * Tries to decrement running count unless already zero
* Possibly triggers termination on success.
* Called by workers when they can't find tasks.
*
* @return true on success
*/ */
final boolean tryDecrementActiveCount() { final boolean tryDecrementRunningCount() {
int c = runControl; int wc = workerCounts;
int nextc = c - 1; if ((wc & RUNNING_COUNT_MASK) == 0)
if (!casRunControl(c, nextc))
return false; return false;
if (canTerminateOnShutdown(nextc)) return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
terminateOnShutdown(); wc, wc - ONE_RUNNING);
return true; }
/**
* Forces decrement of encoded workerCounts, awaiting nonzero if
* (rarely) necessary when other count updates lag.
*
* @param dr -- either zero or ONE_RUNNING
* @param dt -- either zero or ONE_TOTAL
*/
private void decrementWorkerCounts(int dr, int dt) {
for (;;) {
int wc = workerCounts;
if ((wc & RUNNING_COUNT_MASK) - dr < 0 ||
(wc >>> TOTAL_COUNT_SHIFT) - dt < 0) {
if ((runState & TERMINATED) != 0)
return; // lagging termination on a backout
Thread.yield();
}
if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - (dr + dt)))
return;
}
} }
/** /**
* Returns {@code true} if argument represents zero active count * Tries decrementing active count; fails on contention.
* and nonzero runstate, which is the triggering condition for * Called when workers cannot find tasks to run.
* terminating on shutdown.
*/ */
private static boolean canTerminateOnShutdown(int c) { final boolean tryDecrementActiveCount() {
// i.e. least bit is nonzero runState bit int c;
return ((c & -c) >>> 16) != 0; return UNSAFE.compareAndSwapInt(this, runStateOffset,
c = runState, c - 1);
} }
/** /**
* Transition run state to at least the given state. Return true * Advances to at least the given level. Returns true if not
* if not already at least given state. * already in at least the given level.
*/ */
private boolean transitionRunStateTo(int state) { private boolean advanceRunLevel(int level) {
for (;;) { for (;;) {
int c = runControl; int s = runState;
if (runStateOf(c) >= state) if ((s & level) != 0)
return false; return false;
if (casRunControl(c, runControlFor(state, activeCountOf(c)))) if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, s | level))
return true; return true;
} }
} }
// workers array maintenance
/** /**
* Controls whether to add spares to maintain parallelism * Records and returns a workers array index for new worker.
*/ */
private volatile boolean maintainsParallelism; private int recordWorker(ForkJoinWorkerThread w) {
// Try using slot totalCount-1. If not available, scan and/or resize
// Constructors int k = (workerCounts >>> TOTAL_COUNT_SHIFT) - 1;
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
ForkJoinWorkerThread[] ws = workers;
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 = Arrays.copyOf(ws, n << 1);
}
ws[k] = w;
workers = ws; // volatile array write ensures slot visibility
} finally {
lock.unlock();
}
return k;
}
/** /**
* Creates a {@code ForkJoinPool} with parallelism equal to {@link * Nulls out record of worker in workers array.
* 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
* because it does not hold {@link
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/ */
public ForkJoinPool() { private void forgetWorker(ForkJoinWorkerThread w) {
this(Runtime.getRuntime().availableProcessors(), int idx = w.poolIndex;
defaultForkJoinWorkerThreadFactory); // Locking helps method recordWorker avoid unnecessary expansion
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
ForkJoinWorkerThread[] ws = workers;
if (idx >= 0 && idx < ws.length && ws[idx] == w) // verify
ws[idx] = null;
} finally {
lock.unlock();
}
} }
/** /**
* Creates a {@code ForkJoinPool} with the indicated parallelism * Final callback from terminating worker. Removes record of
* level and using the {@linkplain * worker from array, and adjusts counts. If pool is shutting
* #defaultForkJoinWorkerThreadFactory default thread factory}. * down, tries to complete termination.
* *
* @param parallelism the parallelism level * @param w the worker
* @throws IllegalArgumentException if parallelism less than or
* 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
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/ */
public ForkJoinPool(int parallelism) { final void workerTerminated(ForkJoinWorkerThread w) {
this(parallelism, defaultForkJoinWorkerThreadFactory); forgetWorker(w);
decrementWorkerCounts(w.isTrimmed()? 0 : ONE_RUNNING, ONE_TOTAL);
while (w.stealCount != 0) // collect final count
tryAccumulateStealCount(w);
tryTerminate(false);
} }
// Waiting for and signalling events
/** /**
* Creates a {@code ForkJoinPool} with parallelism equal to {@link * Releases workers blocked on a count not equal to current count.
* java.lang.Runtime#availableProcessors}, and using the given * Normally called after precheck that eventWaiters isn't zero to
* thread factory. * avoid wasted array checks. Gives up upon a change in count or
* * upon releasing two workers, letting others take over.
* @param factory the factory for creating new threads
* @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
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/ */
public ForkJoinPool(ForkJoinWorkerThreadFactory factory) { private void releaseEventWaiters() {
this(Runtime.getRuntime().availableProcessors(), factory); ForkJoinWorkerThread[] ws = workers;
int n = ws.length;
long h = eventWaiters;
int ec = eventCount;
boolean releasedOne = false;
ForkJoinWorkerThread w; int id;
while ((id = ((int)(h & WAITER_ID_MASK)) - 1) >= 0 &&
(int)(h >>> EVENT_COUNT_SHIFT) != ec &&
id < n && (w = ws[id]) != null) {
if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
h, w.nextWaiter)) {
LockSupport.unpark(w);
if (releasedOne) // exit on second release
break;
releasedOne = true;
}
if (eventCount != ec)
break;
h = eventWaiters;
}
} }
/** /**
* Creates a {@code ForkJoinPool} with the given parallelism and * Tries to advance eventCount and releases waiters. Called only
* thread factory. * from workers.
*
* @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 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
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/ */
public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory) { final void signalWork() {
if (parallelism <= 0 || parallelism > MAX_THREADS) int c; // try to increment event count -- CAS failure OK
throw new IllegalArgumentException(); UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
if (factory == null) if (eventWaiters != 0L)
throw new NullPointerException(); releaseEventWaiters();
checkPermission();
this.factory = factory;
this.parallelism = parallelism;
this.maxPoolSize = MAX_THREADS;
this.maintainsParallelism = true;
this.poolNumber = poolNumberGenerator.incrementAndGet();
this.workerLock = new ReentrantLock();
this.termination = workerLock.newCondition();
this.stealCount = new AtomicLong();
this.submissionQueue = new LinkedTransferQueue<ForkJoinTask<?>>();
// worker array and workers are lazily constructed
} }
/** /**
* Creates a new worker thread using factory. * Adds the given worker to event queue and blocks until
* terminating or event count advances from the given value
* *
* @param index the index to assign worker * @param w the calling worker thread
* @return new worker, or null if factory failed * @param ec the count
*/ */
private ForkJoinWorkerThread createWorker(int index) { private void eventSync(ForkJoinWorkerThread w, int ec) {
Thread.UncaughtExceptionHandler h = ueh; long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1));
ForkJoinWorkerThread w = factory.newThread(this); long h;
if (w != null) { while ((runState < SHUTDOWN || !tryTerminate(false)) &&
w.poolIndex = index; (((int)((h = eventWaiters) & WAITER_ID_MASK)) == 0 ||
w.setDaemon(true); (int)(h >>> EVENT_COUNT_SHIFT) == ec) &&
w.setAsyncMode(locallyFifo); eventCount == ec) {
w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index); if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
if (h != null) w.nextWaiter = h, nh)) {
w.setUncaughtExceptionHandler(h); awaitEvent(w, ec);
break;
}
} }
return w;
} }
/** /**
* Returns a good size for worker array given pool size. * Blocks the given worker (that has already been entered as an
* Currently requires size to be a power of two. * event waiter) until terminating or event count advances from
*/ * the given value. The oldest (first) waiter uses a timed wait to
private static int arraySizeFor(int poolSize) { * occasionally one-by-one shrink the number of workers (to a
if (poolSize <= 1) * minimum of one) if the pool has not been used for extended
return 1; * periods.
// See Hackers Delight, sec 3.2 *
int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1); * @param w the calling worker thread
c |= c >>> 1; * @param ec the count
c |= c >>> 2; */
c |= c >>> 4; private void awaitEvent(ForkJoinWorkerThread w, int ec) {
c |= c >>> 8; while (eventCount == ec) {
c |= c >>> 16; if (tryAccumulateStealCount(w)) { // transfer while idle
return c + 1; boolean untimed = (w.nextWaiter != 0L ||
(workerCounts & RUNNING_COUNT_MASK) <= 1);
long startTime = untimed? 0 : System.nanoTime();
Thread.interrupted(); // clear/ignore interrupt
if (eventCount != ec || w.runState != 0 ||
runState >= TERMINATING) // recheck after clear
break;
if (untimed)
LockSupport.park(w);
else {
LockSupport.parkNanos(w, SHRINK_RATE_NANOS);
if (eventCount != ec || w.runState != 0 ||
runState >= TERMINATING)
break;
if (System.nanoTime() - startTime >= SHRINK_RATE_NANOS)
tryShutdownUnusedWorker(ec);
}
}
}
} }
// Maintaining parallelism
/** /**
* Creates or resizes array if necessary to hold newLength. * Pushes worker onto the spare stack.
* Call only under exclusion.
*
* @return the array
*/ */
private ForkJoinWorkerThread[] ensureWorkerArrayCapacity(int newLength) { final void pushSpare(ForkJoinWorkerThread w) {
ForkJoinWorkerThread[] ws = workers; int ns = (++w.spareCount << SPARE_COUNT_SHIFT) | (w.poolIndex + 1);
if (ws == null) do {} while (!UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
return workers = new ForkJoinWorkerThread[arraySizeFor(newLength)]; w.nextSpare = spareWaiters,ns));
else if (newLength > ws.length)
return workers = Arrays.copyOf(ws, arraySizeFor(newLength));
else
return ws;
} }
/** /**
* Tries to shrink workers into smaller array after one or more terminate. * Tries (once) to resume a spare if the number of running
* threads is less than target.
*/ */
private void tryShrinkWorkerArray() { private void tryResumeSpare() {
int sw, id;
ForkJoinWorkerThread[] ws = workers; ForkJoinWorkerThread[] ws = workers;
if (ws != null) { int n = ws.length;
int len = ws.length; ForkJoinWorkerThread w;
int last = len - 1; if ((sw = spareWaiters) != 0 &&
while (last >= 0 && ws[last] == null) (id = (sw & SPARE_ID_MASK) - 1) >= 0 &&
--last; id < n && (w = ws[id]) != null &&
int newLength = arraySizeFor(last+1); (workerCounts & RUNNING_COUNT_MASK) < parallelism &&
if (newLength < len) spareWaiters == sw &&
workers = Arrays.copyOf(ws, newLength); UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
sw, w.nextSpare)) {
int c; // increment running count before resume
do {} while (!UNSAFE.compareAndSwapInt
(this, workerCountsOffset,
c = workerCounts, c + ONE_RUNNING));
if (w.tryUnsuspend())
LockSupport.unpark(w);
else // back out if w was shutdown
decrementWorkerCounts(ONE_RUNNING, 0);
} }
} }
/** /**
* Initializes workers if necessary. * Tries to increase the number of running workers if below target
*/ * parallelism: If a spare exists tries to resume it via
final void ensureWorkerInitialization() { * tryResumeSpare. Otherwise, if not enough total workers or all
ForkJoinWorkerThread[] ws = workers; * existing workers are busy, adds a new worker. In all cases also
if (ws == null) { * helps wake up releasable workers waiting for work.
final ReentrantLock lock = this.workerLock; */
lock.lock(); private void helpMaintainParallelism() {
try { int pc = parallelism;
ws = workers; int wc, rs, tc;
if (ws == null) { while (((wc = workerCounts) & RUNNING_COUNT_MASK) < pc &&
int ps = parallelism; (rs = runState) < TERMINATING) {
ws = ensureWorkerArrayCapacity(ps); if (spareWaiters != 0)
for (int i = 0; i < ps; ++i) { tryResumeSpare();
ForkJoinWorkerThread w = createWorker(i); else if ((tc = wc >>> TOTAL_COUNT_SHIFT) >= MAX_WORKERS ||
if (w != null) { (tc >= pc && (rs & ACTIVE_COUNT_MASK) != tc))
ws[i] = w; break; // enough total
w.start(); else if (runState == rs && workerCounts == wc &&
updateWorkerCount(1); UNSAFE.compareAndSwapInt(this, workerCountsOffset, wc,
} wc + (ONE_RUNNING|ONE_TOTAL))) {
ForkJoinWorkerThread w = null;
try {
w = factory.newThread(this);
} finally { // adjust on null or exceptional factory return
if (w == null) {
decrementWorkerCounts(ONE_RUNNING, ONE_TOTAL);
tryTerminate(false); // handle failure during shutdown
} }
} }
} finally { if (w == null)
lock.unlock(); break;
w.start(recordWorker(w), ueh);
if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc) {
int c; // advance event count
UNSAFE.compareAndSwapInt(this, eventCountOffset,
c = eventCount, c+1);
break; // add at most one unless total below target
}
} }
} }
if (eventWaiters != 0L)
releaseEventWaiters();
} }
/** /**
* Worker creation and startup for threads added via setParallelism. * Callback from the oldest waiter in awaitEvent waking up after a
* period of non-use. If all workers are idle, tries (once) to
* shutdown an event waiter or a spare, if one exists. Note that
* we don't need CAS or locks here because the method is called
* only from one thread occasionally waking (and even misfires are
* OK). Note that until the shutdown worker fully terminates,
* workerCounts will overestimate total count, which is tolerable.
*
* @param ec the event count waited on by caller (to abort
* attempt if count has since changed).
*/ */
private void createAndStartAddedWorkers() { private void tryShutdownUnusedWorker(int ec) {
resumeAllSpares(); // Allow spares to convert to nonspare if (runState == 0 && eventCount == ec) { // only trigger if all idle
int ps = parallelism; ForkJoinWorkerThread[] ws = workers;
ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(ps); int n = ws.length;
int len = ws.length; ForkJoinWorkerThread w = null;
// Sweep through slots, to keep lowest indices most populated boolean shutdown = false;
int k = 0; int sw;
while (k < len) { long h;
if (ws[k] != null) { if ((sw = spareWaiters) != 0) { // prefer killing spares
++k; int id = (sw & SPARE_ID_MASK) - 1;
continue; if (id >= 0 && id < n && (w = ws[id]) != null &&
UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
sw, w.nextSpare))
shutdown = true;
} }
int s = workerCounts; else if ((h = eventWaiters) != 0L) {
int tc = totalCountOf(s); long nh;
int rc = runningCountOf(s); int id = ((int)(h & WAITER_ID_MASK)) - 1;
if (rc >= ps || tc >= ps) if (id >= 0 && id < n && (w = ws[id]) != null &&
break; (nh = w.nextWaiter) != 0L && // keep at least one worker
if (casWorkerCounts (s, workerCountsFor(tc+1, rc+1))) { UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh))
ForkJoinWorkerThread w = createWorker(k); shutdown = true;
if (w != null) { }
ws[k++] = w; if (w != null && shutdown) {
w.start(); w.shutdown();
} LockSupport.unpark(w);
else { }
updateWorkerCount(-1); // back out on failed creation }
releaseEventWaiters(); // in case of interference
}
/**
* Callback from workers invoked upon each top-level action (i.e.,
* stealing a task or taking a submission and running it).
* Performs one or more of the following:
*
* 1. If the worker is active and either did not run a task
* or there are too many workers, try to set its active status
* to inactive and update activeCount. On contention, we may
* try again in this or a subsequent call.
*
* 2. If not enough total workers, help create some.
*
* 3. If there are too many running workers, suspend this worker
* (first forcing inactive if necessary). If it is not needed,
* it may be shutdown while suspended (via
* tryShutdownUnusedWorker). Otherwise, upon resume it
* rechecks running thread count and need for event sync.
*
* 4. If worker did not run a task, await the next task event via
* eventSync if necessary (first forcing inactivation), upon
* which the worker may be shutdown via
* tryShutdownUnusedWorker. Otherwise, help release any
* existing event waiters that are now releasable,
*
* @param w the worker
* @param ran true if worker ran a task since last call to this method
*/
final void preStep(ForkJoinWorkerThread w, boolean ran) {
int wec = w.lastEventCount;
boolean active = w.active;
boolean inactivate = false;
int pc = parallelism;
int rs;
while (w.runState == 0 && (rs = runState) < TERMINATING) {
if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) &&
UNSAFE.compareAndSwapInt(this, runStateOffset, rs, rs - 1))
inactivate = active = w.active = false;
int wc = workerCounts;
if ((wc & RUNNING_COUNT_MASK) > pc) {
if (!(inactivate |= active) && // must inactivate to suspend
workerCounts == wc && // try to suspend as spare
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING))
w.suspendAsSpare();
}
else if ((wc >>> TOTAL_COUNT_SHIFT) < pc)
helpMaintainParallelism(); // not enough workers
else if (!ran) {
long h = eventWaiters;
int ec = eventCount;
if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec)
releaseEventWaiters(); // release others before waiting
else if (ec != wec) {
w.lastEventCount = ec; // no need to wait
break; break;
} }
else if (!(inactivate |= active))
eventSync(w, wec); // must inactivate before sync
} }
else
break;
} }
} }
// Execution methods /**
* Helps and/or blocks awaiting join of the given task.
* See above for explanation.
*
* @param joinMe the task to join
* @param worker the current worker thread
*/
final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker) {
int retries = 2 + (parallelism >> 2); // #helpJoins before blocking
while (joinMe.status >= 0) {
int wc;
worker.helpJoinTask(joinMe);
if (joinMe.status < 0)
break;
else if (retries > 0)
--retries;
else if (((wc = workerCounts) & RUNNING_COUNT_MASK) != 0 &&
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING)) {
int stat, c; long h;
while ((stat = joinMe.status) >= 0 &&
(h = eventWaiters) != 0L && // help release others
(int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
releaseEventWaiters();
if (stat >= 0 &&
((workerCounts & RUNNING_COUNT_MASK) == 0 ||
(stat =
joinMe.internalAwaitDone(JOIN_TIMEOUT_MILLIS)) >= 0))
helpMaintainParallelism(); // timeout or no running workers
do {} while (!UNSAFE.compareAndSwapInt
(this, workerCountsOffset,
c = workerCounts, c + ONE_RUNNING));
if (stat < 0)
break; // else restart
}
}
}
/** /**
* Common code for execute, invoke and submit * Same idea as awaitJoin, but no helping, retries, or timeouts.
*/ */
private <T> void doSubmit(ForkJoinTask<T> task) { final void awaitBlocker(ManagedBlocker blocker)
if (task == null) throws InterruptedException {
throw new NullPointerException(); while (!blocker.isReleasable()) {
if (isShutdown()) int wc = workerCounts;
throw new RejectedExecutionException(); if ((wc & RUNNING_COUNT_MASK) != 0 &&
if (workers == null) UNSAFE.compareAndSwapInt(this, workerCountsOffset,
ensureWorkerInitialization(); wc, wc - ONE_RUNNING)) {
submissionQueue.offer(task); try {
signalIdleWorkers(); while (!blocker.isReleasable()) {
long h = eventWaiters;
if (h != 0L &&
(int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
releaseEventWaiters();
else if ((workerCounts & RUNNING_COUNT_MASK) == 0 &&
runState < TERMINATING)
helpMaintainParallelism();
else if (blocker.block())
break;
}
} finally {
int c;
do {} while (!UNSAFE.compareAndSwapInt
(this, workerCountsOffset,
c = workerCounts, c + ONE_RUNNING));
}
break;
}
}
} }
/** /**
* Performs the given task, returning its result upon completion. * Possibly initiates and/or completes termination.
* *
* @param task the task * @param now if true, unconditionally terminate, else only
* @return the task's result * if shutdown and empty queue and no active workers
* @throws NullPointerException if the task is null * @return true if now terminating or terminated
* @throws RejectedExecutionException if the task cannot be */
* scheduled for execution private boolean tryTerminate(boolean now) {
*/ if (now)
public <T> T invoke(ForkJoinTask<T> task) { advanceRunLevel(SHUTDOWN); // ensure at least SHUTDOWN
doSubmit(task); else if (runState < SHUTDOWN ||
return task.join(); !submissionQueue.isEmpty() ||
(runState & ACTIVE_COUNT_MASK) != 0)
return false;
if (advanceRunLevel(TERMINATING))
startTerminating();
// Finish now if all threads terminated; else in some subsequent call
if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) {
advanceRunLevel(TERMINATED);
termination.arrive();
}
return true;
} }
/** /**
* Arranges for (asynchronous) execution of the given task. * Actions on transition to TERMINATING
* *
* @param task the task * Runs up to four passes through workers: (0) shutting down each
* @throws NullPointerException if the task is null * (without waking up if parked) to quickly spread notifications
* @throws RejectedExecutionException if the task cannot be * without unnecessary bouncing around event queues etc (1) wake
* scheduled for execution * up and help cancel tasks (2) interrupt (3) mop up races with
* interrupted workers
*/
private void startTerminating() {
cancelSubmissions();
for (int passes = 0; passes < 4 && workerCounts != 0; ++passes) {
int c; // advance event count
UNSAFE.compareAndSwapInt(this, eventCountOffset,
c = eventCount, c+1);
eventWaiters = 0L; // clobber lists
spareWaiters = 0;
for (ForkJoinWorkerThread w : workers) {
if (w != null) {
w.shutdown();
if (passes > 0 && !w.isTerminated()) {
w.cancelTasks();
LockSupport.unpark(w);
if (passes > 1) {
try {
w.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
}
}
}
/**
* Clears out and cancels submissions, ignoring exceptions.
*/ */
public void execute(ForkJoinTask<?> task) { private void cancelSubmissions() {
doSubmit(task); ForkJoinTask<?> task;
while ((task = submissionQueue.poll()) != null) {
try {
task.cancel(false);
} catch (Throwable ignore) {
}
}
} }
// AbstractExecutorService methods // misc support for ForkJoinWorkerThread
/** /**
* @throws NullPointerException if the task is null * Returns pool number.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
*/ */
public void execute(Runnable task) { final int getPoolNumber() {
ForkJoinTask<?> job; return poolNumber;
if (task instanceof ForkJoinTask<?>) // avoid re-wrap }
job = (ForkJoinTask<?>) task;
else /**
job = ForkJoinTask.adapt(task, null); * Tries to accumulate steal count from a worker, clearing
doSubmit(job); * the worker's value if successful.
*
* @return true if worker steal count now zero
*/
final boolean tryAccumulateStealCount(ForkJoinWorkerThread w) {
int sc = w.stealCount;
long c = stealCount;
// CAS even if zero, for fence effects
if (UNSAFE.compareAndSwapLong(this, stealCountOffset, c, c + sc)) {
if (sc != 0)
w.stealCount = 0;
return true;
}
return sc == 0;
} }
/** /**
* Returns the approximate (non-atomic) number of idle threads per
* active thread.
*/
final int idlePerActive() {
int pc = parallelism; // use parallelism, not rc
int ac = runState; // no mask -- artificially boosts during shutdown
// Use exact results for small values, saturate past 4
return ((pc <= ac) ? 0 :
(pc >>> 1 <= ac) ? 1 :
(pc >>> 2 <= ac) ? 3 :
pc >>> 3);
}
// Public and protected methods
// Constructors
/**
* Creates a {@code ForkJoinPool} with parallelism equal to {@link
* java.lang.Runtime#availableProcessors}, using the {@linkplain
* #defaultForkJoinWorkerThreadFactory default thread factory},
* no UncaughtExceptionHandler, and non-async LIFO processing mode.
*
* @throws SecurityException if a security manager exists and
* the caller is not permitted to modify threads
* because it does not hold {@link
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool() {
this(Runtime.getRuntime().availableProcessors(),
defaultForkJoinWorkerThreadFactory, null, false);
}
/**
* Creates a {@code ForkJoinPool} with the indicated parallelism
* level, the {@linkplain
* #defaultForkJoinWorkerThreadFactory default thread factory},
* no UncaughtExceptionHandler, and non-async LIFO processing mode.
*
* @param parallelism the parallelism level
* @throws IllegalArgumentException if parallelism less than or
* 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
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool(int parallelism) {
this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}
/**
* Creates a {@code ForkJoinPool} with the given parameters.
*
* @param parallelism the parallelism level. For default value,
* use {@link java.lang.Runtime#availableProcessors}.
* @param factory the factory for creating new threads. For default value,
* use {@link #defaultForkJoinWorkerThreadFactory}.
* @param handler the handler for internal worker threads that
* terminate due to unrecoverable errors encountered while executing
* tasks. For default value, use {@code null}.
* @param asyncMode if true,
* establishes local first-in-first-out scheduling mode for forked
* tasks that are never joined. This mode may be more appropriate
* than default locally stack-based mode in applications in which
* worker threads only process event-style asynchronous tasks.
* For default value, use {@code false}.
* @throws IllegalArgumentException if parallelism less than or
* 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
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
Thread.UncaughtExceptionHandler handler,
boolean asyncMode) {
checkPermission();
if (factory == null)
throw new NullPointerException();
if (parallelism <= 0 || parallelism > MAX_WORKERS)
throw new IllegalArgumentException();
this.parallelism = parallelism;
this.factory = factory;
this.ueh = handler;
this.locallyFifo = asyncMode;
int arraySize = initialArraySizeFor(parallelism);
this.workers = new ForkJoinWorkerThread[arraySize];
this.submissionQueue = new LinkedTransferQueue<ForkJoinTask<?>>();
this.workerLock = new ReentrantLock();
this.termination = new Phaser(1);
this.poolNumber = poolNumberGenerator.incrementAndGet();
}
/**
* Returns initial power of two size for workers array.
* @param pc the initial parallelism level
*/
private static int initialArraySizeFor(int pc) {
// If possible, initially allocate enough space for one spare
int size = pc < MAX_WORKERS ? pc + 1 : MAX_WORKERS;
// See Hackers Delight, sec 3.2. We know MAX_WORKERS < (1 >>> 16)
size |= size >>> 1;
size |= size >>> 2;
size |= size >>> 4;
size |= size >>> 8;
return size + 1;
}
// Execution methods
/**
* Common code for execute, invoke and submit
*/
private <T> void doSubmit(ForkJoinTask<T> task) {
if (task == null)
throw new NullPointerException();
if (runState >= SHUTDOWN)
throw new RejectedExecutionException();
submissionQueue.offer(task);
int c; // try to increment event count -- CAS failure OK
UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
helpMaintainParallelism(); // create, start, or resume some workers
}
/**
* Performs the given task, returning its result upon completion.
*
* @param task the task
* @return the task's result
* @throws NullPointerException if the task is null * @throws NullPointerException if the task is null
* @throws RejectedExecutionException if the task cannot be * @throws RejectedExecutionException if the task cannot be
* scheduled for execution * scheduled for execution
*/ */
public <T> ForkJoinTask<T> submit(Callable<T> task) { public <T> T invoke(ForkJoinTask<T> task) {
ForkJoinTask<T> job = ForkJoinTask.adapt(task); doSubmit(task);
doSubmit(job); return task.join();
return job;
} }
/** /**
* Arranges for (asynchronous) execution of the given task.
*
* @param task the task
* @throws NullPointerException if the task is null * @throws NullPointerException if the task is null
* @throws RejectedExecutionException if the task cannot be * @throws RejectedExecutionException if the task cannot be
* scheduled for execution * scheduled for execution
*/ */
public <T> ForkJoinTask<T> submit(Runnable task, T result) { public void execute(ForkJoinTask<?> task) {
ForkJoinTask<T> job = ForkJoinTask.adapt(task, result); doSubmit(task);
doSubmit(job);
return job;
} }
// AbstractExecutorService methods
/** /**
* @throws NullPointerException if the task is null * @throws NullPointerException if the task is null
* @throws RejectedExecutionException if the task cannot be * @throws RejectedExecutionException if the task cannot be
* scheduled for execution * scheduled for execution
*/ */
public ForkJoinTask<?> submit(Runnable task) { public void execute(Runnable task) {
ForkJoinTask<?> job; ForkJoinTask<?> job;
if (task instanceof ForkJoinTask<?>) // avoid re-wrap if (task instanceof ForkJoinTask<?>) // avoid re-wrap
job = (ForkJoinTask<?>) task; job = (ForkJoinTask<?>) task;
else else
job = ForkJoinTask.adapt(task, null); job = ForkJoinTask.adapt(task, null);
doSubmit(job); doSubmit(job);
return job;
} }
/** /**
...@@ -712,6 +1385,42 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -712,6 +1385,42 @@ public class ForkJoinPool extends AbstractExecutorService {
return task; return task;
} }
/**
* @throws NullPointerException if the task is null
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
*/
public <T> ForkJoinTask<T> submit(Callable<T> task) {
ForkJoinTask<T> 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 <T> ForkJoinTask<T> submit(Runnable task, T result) {
ForkJoinTask<T> 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
job = (ForkJoinTask<?>) task;
else
job = ForkJoinTask.adapt(task, null);
doSubmit(job);
return job;
}
/** /**
* @throws NullPointerException {@inheritDoc} * @throws NullPointerException {@inheritDoc}
...@@ -725,7 +1434,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -725,7 +1434,7 @@ public class ForkJoinPool extends AbstractExecutorService {
invoke(new InvokeAll<T>(forkJoinTasks)); invoke(new InvokeAll<T>(forkJoinTasks));
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks; List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks;
return futures; return futures;
} }
...@@ -739,8 +1448,6 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -739,8 +1448,6 @@ public class ForkJoinPool extends AbstractExecutorService {
private static final long serialVersionUID = -7914297376763021607L; private static final long serialVersionUID = -7914297376763021607L;
} }
// Configuration and status settings and queries
/** /**
* Returns the factory used for constructing new workers. * Returns the factory used for constructing new workers.
* *
...@@ -757,84 +1464,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -757,84 +1464,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the handler, or {@code null} if none * @return the handler, or {@code null} if none
*/ */
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
Thread.UncaughtExceptionHandler h; return ueh;
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
h = ueh;
} finally {
lock.unlock();
}
return h;
}
/**
* Sets the handler for internal worker threads that terminate due
* to unrecoverable errors encountered while executing tasks.
* Unless set, the current default or ThreadGroup handler is used
* as handler.
*
* @param h the new handler
* @return the old handler, or {@code null} if none
* @throws SecurityException if a security manager exists and
* the caller is not permitted to modify threads
* because it does not hold {@link
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public Thread.UncaughtExceptionHandler
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) {
checkPermission();
Thread.UncaughtExceptionHandler old = null;
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
old = ueh;
ueh = h;
ForkJoinWorkerThread[] ws = workers;
if (ws != null) {
for (int i = 0; i < ws.length; ++i) {
ForkJoinWorkerThread w = ws[i];
if (w != null)
w.setUncaughtExceptionHandler(h);
}
}
} finally {
lock.unlock();
}
return old;
}
/**
* Sets the target parallelism level of this pool.
*
* @param parallelism the target parallelism
* @throws IllegalArgumentException if parallelism less than or
* equal to zero or greater than maximum size bounds
* @throws SecurityException if a security manager exists and
* the caller is not permitted to modify threads
* because it does not hold {@link
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public void setParallelism(int parallelism) {
checkPermission();
if (parallelism <= 0 || parallelism > maxPoolSize)
throw new IllegalArgumentException();
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
if (isProcessingTasks()) {
int p = this.parallelism;
this.parallelism = parallelism;
if (parallelism > p)
createAndStartAddedWorkers();
else
trimSpares();
}
} finally {
lock.unlock();
}
signalIdleWorkers();
} }
/** /**
...@@ -848,92 +1478,14 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -848,92 +1478,14 @@ public class ForkJoinPool extends AbstractExecutorService {
/** /**
* Returns the number of worker threads that have started but not * Returns the number of worker threads that have started but not
* yet terminated. This result returned by this method may differ * yet terminated. The result returned by this method may differ
* from {@link #getParallelism} when threads are created to * from {@link #getParallelism} when threads are created to
* maintain parallelism when others are cooperatively blocked. * maintain parallelism when others are cooperatively blocked.
* *
* @return the number of worker threads * @return the number of worker threads
*/ */
public int getPoolSize() { public int getPoolSize() {
return totalCountOf(workerCounts); return workerCounts >>> TOTAL_COUNT_SHIFT;
}
/**
* Returns the maximum number of threads allowed to exist in the
* pool. Unless set using {@link #setMaximumPoolSize}, the
* maximum is an implementation-defined value designed only to
* prevent runaway growth.
*
* @return the maximum
*/
public int getMaximumPoolSize() {
return maxPoolSize;
}
/**
* Sets the maximum number of threads allowed to exist in the
* 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
*/
public void setMaximumPoolSize(int newMax) {
if (newMax < 0 || newMax > MAX_THREADS)
throw new IllegalArgumentException();
maxPoolSize = newMax;
}
/**
* Returns {@code true} if this pool dynamically maintains its
* target parallelism level. If false, new threads are added only
* to avoid possible starvation. This setting is by default true.
*
* @return {@code true} if maintains parallelism
*/
public boolean getMaintainsParallelism() {
return maintainsParallelism;
}
/**
* Sets whether this pool dynamically maintains its target
* parallelism level. If false, new threads are added only to
* avoid possible starvation.
*
* @param enable {@code true} to maintain parallelism
*/
public void setMaintainsParallelism(boolean enable) {
maintainsParallelism = enable;
}
/**
* Establishes local first-in-first-out scheduling mode for forked
* tasks that are never joined. This mode may be more appropriate
* than default locally stack-based mode in applications in which
* worker threads only process asynchronous tasks. This method is
* designed to be invoked only when the pool is quiescent, and
* typically only before any tasks are submitted. The effects of
* invocations at other times may be unpredictable.
*
* @param async if {@code true}, use locally FIFO scheduling
* @return the previous mode
* @see #getAsyncMode
*/
public boolean setAsyncMode(boolean async) {
boolean oldMode = locallyFifo;
locallyFifo = async;
ForkJoinWorkerThread[] ws = workers;
if (ws != null) {
for (int i = 0; i < ws.length; ++i) {
ForkJoinWorkerThread t = ws[i];
if (t != null)
t.setAsyncMode(async);
}
}
return oldMode;
} }
/** /**
...@@ -941,7 +1493,6 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -941,7 +1493,6 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduling mode for forked tasks that are never joined. * scheduling mode for forked tasks that are never joined.
* *
* @return {@code true} if this pool uses async mode * @return {@code true} if this pool uses async mode
* @see #setAsyncMode
*/ */
public boolean getAsyncMode() { public boolean getAsyncMode() {
return locallyFifo; return locallyFifo;
...@@ -950,12 +1501,13 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -950,12 +1501,13 @@ public class ForkJoinPool extends AbstractExecutorService {
/** /**
* Returns an estimate of the number of worker threads that are * Returns an estimate of the number of worker threads that are
* not blocked waiting to join tasks or for other managed * not blocked waiting to join tasks or for other managed
* synchronization. * synchronization. This method may overestimate the
* number of running threads.
* *
* @return the number of worker threads * @return the number of worker threads
*/ */
public int getRunningThreadCount() { public int getRunningThreadCount() {
return runningCountOf(workerCounts); return workerCounts & RUNNING_COUNT_MASK;
} }
/** /**
...@@ -966,19 +1518,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -966,19 +1518,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of active threads * @return the number of active threads
*/ */
public int getActiveThreadCount() { public int getActiveThreadCount() {
return activeCountOf(runControl); return runState & ACTIVE_COUNT_MASK;
}
/**
* Returns an estimate of the number of threads that are currently
* idle waiting for tasks. This method may underestimate the
* number of idle threads.
*
* @return the number of idle threads
*/
final int getIdleThreadCount() {
int c = runningCountOf(workerCounts) - activeCountOf(runControl);
return (c <= 0) ? 0 : c;
} }
/** /**
...@@ -993,7 +1533,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -993,7 +1533,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if all threads are currently idle * @return {@code true} if all threads are currently idle
*/ */
public boolean isQuiescent() { public boolean isQuiescent() {
return activeCountOf(runControl) == 0; return (runState & ACTIVE_COUNT_MASK) == 0;
} }
/** /**
...@@ -1008,17 +1548,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1008,17 +1548,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of steals * @return the number of steals
*/ */
public long getStealCount() { public long getStealCount() {
return stealCount.get(); return stealCount;
}
/**
* Accumulates steal count from a worker.
* Call only when worker known to be idle.
*/
private void updateStealCount(ForkJoinWorkerThread w) {
int sc = w.getAndClearStealCount();
if (sc != 0)
stealCount.addAndGet(sc);
} }
/** /**
...@@ -1033,14 +1563,9 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1033,14 +1563,9 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
public long getQueuedTaskCount() { public long getQueuedTaskCount() {
long count = 0; long count = 0;
ForkJoinWorkerThread[] ws = workers; for (ForkJoinWorkerThread w : workers)
if (ws != null) { if (w != null)
for (int i = 0; i < ws.length; ++i) { count += w.getQueueSize();
ForkJoinWorkerThread t = ws[i];
if (t != null)
count += t.getQueueSize();
}
}
return count; return count;
} }
...@@ -1094,16 +1619,11 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1094,16 +1619,11 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of elements transferred * @return the number of elements transferred
*/ */
protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) { protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
int n = submissionQueue.drainTo(c); int count = submissionQueue.drainTo(c);
ForkJoinWorkerThread[] ws = workers; for (ForkJoinWorkerThread w : workers)
if (ws != null) { if (w != null)
for (int i = 0; i < ws.length; ++i) { count += w.drainTasksTo(c);
ForkJoinWorkerThread w = ws[i]; return count;
if (w != null)
n += w.drainTasksTo(c);
}
}
return n;
} }
/** /**
...@@ -1114,36 +1634,34 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1114,36 +1634,34 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return a string identifying this pool, as well as its state * @return a string identifying this pool, as well as its state
*/ */
public String toString() { public String toString() {
int ps = parallelism;
int wc = workerCounts;
int rc = runControl;
long st = getStealCount(); long st = getStealCount();
long qt = getQueuedTaskCount(); long qt = getQueuedTaskCount();
long qs = getQueuedSubmissionCount(); long qs = getQueuedSubmissionCount();
int wc = workerCounts;
int tc = wc >>> TOTAL_COUNT_SHIFT;
int rc = wc & RUNNING_COUNT_MASK;
int pc = parallelism;
int rs = runState;
int ac = rs & ACTIVE_COUNT_MASK;
return super.toString() + return super.toString() +
"[" + runStateToString(runStateOf(rc)) + "[" + runLevelToString(rs) +
", parallelism = " + ps + ", parallelism = " + pc +
", size = " + totalCountOf(wc) + ", size = " + tc +
", active = " + activeCountOf(rc) + ", active = " + ac +
", running = " + runningCountOf(wc) + ", running = " + rc +
", steals = " + st + ", steals = " + st +
", tasks = " + qt + ", tasks = " + qt +
", submissions = " + qs + ", submissions = " + qs +
"]"; "]";
} }
private static String runStateToString(int rs) { private static String runLevelToString(int s) {
switch(rs) { return ((s & TERMINATED) != 0 ? "Terminated" :
case RUNNING: return "Running"; ((s & TERMINATING) != 0 ? "Terminating" :
case SHUTDOWN: return "Shutting down"; ((s & SHUTDOWN) != 0 ? "Shutting down" :
case TERMINATING: return "Terminating"; "Running")));
case TERMINATED: return "Terminated";
default: throw new Error("Unknown run state");
}
} }
// lifecycle control
/** /**
* Initiates an orderly shutdown in which previously submitted * Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted. * tasks are executed, but no new tasks will be accepted.
...@@ -1158,23 +1676,8 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1158,23 +1676,8 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
public void shutdown() { public void shutdown() {
checkPermission(); checkPermission();
transitionRunStateTo(SHUTDOWN); advanceRunLevel(SHUTDOWN);
if (canTerminateOnShutdown(runControl)) { tryTerminate(false);
if (workers == null) { // shutting down before workers created
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
if (workers == null) {
terminate();
transitionRunStateTo(TERMINATED);
termination.signalAll();
}
} finally {
lock.unlock();
}
}
terminateOnShutdown();
}
} }
/** /**
...@@ -1195,7 +1698,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1195,7 +1698,7 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
public List<Runnable> shutdownNow() { public List<Runnable> shutdownNow() {
checkPermission(); checkPermission();
terminate(); tryTerminate(true);
return Collections.emptyList(); return Collections.emptyList();
} }
...@@ -1205,7 +1708,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1205,7 +1708,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if all tasks have completed following shut down * @return {@code true} if all tasks have completed following shut down
*/ */
public boolean isTerminated() { public boolean isTerminated() {
return runStateOf(runControl) == TERMINATED; return runState >= TERMINATED;
} }
/** /**
...@@ -1219,7 +1722,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1219,7 +1722,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if terminating but not yet terminated * @return {@code true} if terminating but not yet terminated
*/ */
public boolean isTerminating() { public boolean isTerminating() {
return runStateOf(runControl) == TERMINATING; return (runState & (TERMINATING|TERMINATED)) == TERMINATING;
} }
/** /**
...@@ -1228,15 +1731,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1228,15 +1731,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if this pool has been shut down * @return {@code true} if this pool has been shut down
*/ */
public boolean isShutdown() { public boolean isShutdown() {
return runStateOf(runControl) >= SHUTDOWN; return runState >= SHUTDOWN;
}
/**
* Returns true if pool is not terminating or terminated.
* Used internally to suppress execution when terminating.
*/
final boolean isProcessingTasks() {
return runStateOf(runControl) < TERMINATING;
} }
/** /**
...@@ -1252,585 +1747,10 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1252,585 +1747,10 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
public boolean awaitTermination(long timeout, TimeUnit unit) public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException { throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
for (;;) {
if (isTerminated())
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
lock.unlock();
}
}
// Shutdown and termination support
/**
* Callback from terminating worker. Nulls out the corresponding
* workers slot, and if terminating, tries to terminate; else
* tries to shrink workers array.
*
* @param w the worker
*/
final void workerTerminated(ForkJoinWorkerThread w) {
updateStealCount(w);
updateWorkerCount(-1);
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
ForkJoinWorkerThread[] ws = workers;
if (ws != null) {
int idx = w.poolIndex;
if (idx >= 0 && idx < ws.length && ws[idx] == w)
ws[idx] = null;
if (totalCountOf(workerCounts) == 0) {
terminate(); // no-op if already terminating
transitionRunStateTo(TERMINATED);
termination.signalAll();
}
else if (isProcessingTasks()) {
tryShrinkWorkerArray();
tryResumeSpare(true); // allow replacement
}
}
} finally {
lock.unlock();
}
signalIdleWorkers();
}
/**
* Initiates termination.
*/
private void terminate() {
if (transitionRunStateTo(TERMINATING)) {
stopAllWorkers();
resumeAllSpares();
signalIdleWorkers();
cancelQueuedSubmissions();
cancelQueuedWorkerTasks();
interruptUnterminatedWorkers();
signalIdleWorkers(); // resignal after interrupt
}
}
/**
* Possibly terminates when on shutdown state.
*/
private void terminateOnShutdown() {
if (!hasQueuedSubmissions() && canTerminateOnShutdown(runControl))
terminate();
}
/**
* Clears out and cancels submissions.
*/
private void cancelQueuedSubmissions() {
ForkJoinTask<?> task;
while ((task = pollSubmission()) != null)
task.cancel(false);
}
/**
* Cleans out worker queues.
*/
private void cancelQueuedWorkerTasks() {
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
ForkJoinWorkerThread[] ws = workers;
if (ws != null) {
for (int i = 0; i < ws.length; ++i) {
ForkJoinWorkerThread t = ws[i];
if (t != null)
t.cancelTasks();
}
}
} finally {
lock.unlock();
}
}
/**
* Sets each worker's status to terminating. Requires lock to avoid
* conflicts with add/remove.
*/
private void stopAllWorkers() {
final ReentrantLock lock = this.workerLock;
lock.lock();
try {
ForkJoinWorkerThread[] ws = workers;
if (ws != null) {
for (int i = 0; i < ws.length; ++i) {
ForkJoinWorkerThread t = ws[i];
if (t != null)
t.shutdownNow();
}
}
} finally {
lock.unlock();
}
}
/**
* Interrupts all unterminated workers. This is not required for
* sake of internal control, but may help unstick user code during
* shutdown.
*/
private void interruptUnterminatedWorkers() {
final ReentrantLock lock = this.workerLock;
lock.lock();
try { try {
ForkJoinWorkerThread[] ws = workers; return termination.awaitAdvanceInterruptibly(0, timeout, unit) > 0;
if (ws != null) { } catch (TimeoutException ex) {
for (int i = 0; i < ws.length; ++i) {
ForkJoinWorkerThread t = ws[i];
if (t != null && !t.isTerminated()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
} finally {
lock.unlock();
}
}
/*
* Nodes for event barrier to manage idle threads. Queue nodes
* are basic Treiber stack nodes, also used for spare stack.
*
* The event barrier has an event count and a wait queue (actually
* a Treiber stack). Workers are enabled to look for work when
* the eventCount is incremented. If they fail to find work, they
* may wait for next count. Upon release, threads help others wake
* up.
*
* Synchronization events occur only in enough contexts to
* maintain overall liveness:
*
* - Submission of a new task to the pool
* - Resizes or other changes to the workers array
* - pool termination
* - A worker pushing a task on an empty queue
*
* The case of pushing a task occurs often enough, and is heavy
* enough compared to simple stack pushes, to require special
* 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.
*/
static final class WaitQueueNode {
WaitQueueNode next; // only written before enqueued
volatile ForkJoinWorkerThread thread; // nulled to cancel wait
final long count; // unused for spare stack
WaitQueueNode(long c, ForkJoinWorkerThread w) {
count = c;
thread = w;
}
/**
* Wakes up waiter, returning false if known to already
*/
boolean signal() {
ForkJoinWorkerThread t = thread;
if (t == null)
return false;
thread = null;
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() {
long c = eventCount;
WaitQueueNode q;
while ((q = syncStack) != null && q.count < c) {
if (casBarrierStack(q, null)) {
do {
q.signal();
} while ((q = q.next) != null);
break;
}
}
return c;
}
/**
* Increments event count and releases waiting threads.
*/
private void signalIdleWorkers() {
long c;
do {} while (!casEventCount(c = eventCount, c+1));
ensureSync();
}
/**
* 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).
*/
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();
}
/**
* Waits until event count advances from last value held by
* caller, or if excess threads, caller is resumed as spare, or
* caller or pool is terminating. Updates caller's event on exit.
*
* @param w the calling worker thread
*/
final void sync(ForkJoinWorkerThread w) {
updateStealCount(w); // Transfer w's count while it is idle
while (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) {
long prev = w.lastEventCount;
WaitQueueNode node = null;
WaitQueueNode h;
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);
break;
}
}
long ec = ensureSync();
if (ec != prev) {
w.lastEventCount = ec;
break;
}
}
}
/**
* 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
* call to sync or this method, if so, updating caller's count.
*/
final boolean hasNewSyncEvent(ForkJoinWorkerThread w) {
long lc = w.lastEventCount;
long ec = ensureSync();
if (ec == lc)
return false; return false;
w.lastEventCount = ec;
return true;
}
// Parallelism maintenance
/**
* Decrements running count; if too low, adds spare.
*
* Conceptually, all we need to do here is add or resume a
* spare thread when one is about to block (and remove or
* suspend it later when unblocked -- see suspendIfSpare).
* However, implementing this idea requires coping with
* several problems: we have imperfect information about the
* states of threads. Some count updates can and usually do
* lag run state changes, despite arrangements to keep them
* accurate (for example, when possible, updating counts
* before signalling or resuming), especially when running on
* dynamic JVMs that don't optimize the infrequent paths that
* update counts. Generating too many threads can make these
* problems become worse, because excess threads are more
* likely to be context-switched with others, slowing them all
* down, especially if there is no work available, so all are
* busy scanning or idling. Also, excess spare threads can
* only be suspended or removed when they are idle, not
* immediately when they aren't needed. So adding threads will
* raise parallelism level for longer than necessary. Also,
* FJ applications often encounter highly transient peaks when
* many threads are blocked joining, but for less time than it
* takes to create or resume spares.
*
* @param joinMe if non-null, return early if done
* @param maintainParallelism if true, try to stay within
* target counts, else create only to avoid starvation
* @return true if joinMe known to be done
*/
final boolean preJoin(ForkJoinTask<?> joinMe,
boolean maintainParallelism) {
maintainParallelism &= maintainsParallelism; // overrride
boolean dec = false; // true when running count decremented
while (spareStack == null || !tryResumeSpare(dec)) {
int counts = workerCounts;
if (dec || (dec = casWorkerCounts(counts, --counts))) {
if (!needSpare(counts, maintainParallelism))
break;
if (joinMe.status < 0)
return true;
if (tryAddSpare(counts))
break;
}
}
return false;
}
/**
* Same idea as preJoin
*/
final boolean preBlock(ManagedBlocker blocker,
boolean maintainParallelism) {
maintainParallelism &= maintainsParallelism;
boolean dec = false;
while (spareStack == null || !tryResumeSpare(dec)) {
int counts = workerCounts;
if (dec || (dec = casWorkerCounts(counts, --counts))) {
if (!needSpare(counts, maintainParallelism))
break;
if (blocker.isReleasable())
return true;
if (tryAddSpare(counts))
break;
}
}
return false;
}
/**
* Returns {@code true} if a spare thread appears to be needed.
* If maintaining parallelism, returns true when the deficit in
* running threads is more than the surplus of total threads, and
* there is apparently some work to do. This self-limiting rule
* means that the more threads that have already been added, the
* less parallelism we will tolerate before adding another.
*
* @param counts current worker counts
* @param maintainParallelism try to maintain parallelism
*/
private boolean needSpare(int counts, boolean maintainParallelism) {
int ps = parallelism;
int rc = runningCountOf(counts);
int tc = totalCountOf(counts);
int runningDeficit = ps - rc;
int totalSurplus = tc - ps;
return (tc < maxPoolSize &&
(rc == 0 || totalSurplus < 0 ||
(maintainParallelism &&
runningDeficit > totalSurplus &&
ForkJoinWorkerThread.hasQueuedTasks(workers))));
}
/**
* Adds a spare worker if lock available and no more than the
* expected numbers of threads exist.
*
* @return true if successful
*/
private boolean tryAddSpare(int expectedCounts) {
final ReentrantLock lock = this.workerLock;
int expectedRunning = runningCountOf(expectedCounts);
int expectedTotal = totalCountOf(expectedCounts);
boolean success = false;
boolean locked = false;
// confirm counts while locking; CAS after obtaining lock
try {
for (;;) {
int s = workerCounts;
int tc = totalCountOf(s);
int rc = runningCountOf(s);
if (rc > expectedRunning || tc > expectedTotal)
break;
if (!locked && !(locked = lock.tryLock()))
break;
if (casWorkerCounts(s, workerCountsFor(tc+1, rc+1))) {
createAndStartSpare(tc);
success = true;
break;
}
}
} finally {
if (locked)
lock.unlock();
}
return success;
}
/**
* Adds the kth spare worker. On entry, pool counts are already
* adjusted to reflect addition.
*/
private void createAndStartSpare(int k) {
ForkJoinWorkerThread w = null;
ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(k + 1);
int len = ws.length;
// Probably, we can place at slot k. If not, find empty slot
if (k < len && ws[k] != null) {
for (k = 0; k < len && ws[k] != null; ++k)
;
}
if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) {
ws[k] = w;
w.start();
}
else
updateWorkerCount(-1); // adjust on failure
signalIdleWorkers();
}
/**
* Suspends calling thread w if there are excess threads. Called
* only from sync. Spares are enqueued in a Treiber stack using
* the same WaitQueueNodes as barriers. They are resumed mainly
* in preJoin, but are also woken on pool events that require all
* threads to check run state.
*
* @param w the caller
*/
private boolean suspendIfSpare(ForkJoinWorkerThread w) {
WaitQueueNode node = null;
int s;
while (parallelism < runningCountOf(s = workerCounts)) {
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;
}
}
return false;
}
/**
* Tries to pop and resume a spare thread.
*
* @param updateCount if true, increment running count on success
* @return true if successful
*/
private boolean tryResumeSpare(boolean updateCount) {
WaitQueueNode q;
while ((q = spareStack) != null) {
if (casSpareStack(q, q.next)) {
if (updateCount)
updateRunningCount(1);
q.signal();
return true;
}
}
return false;
}
/**
* Pops and resumes all spare threads. Same idea as ensureSync.
*
* @return true if any spares released
*/
private boolean resumeAllSpares() {
WaitQueueNode q;
while ( (q = spareStack) != null) {
if (casSpareStack(q, null)) {
do {
updateRunningCount(1);
q.signal();
} while ((q = q.next) != null);
return true;
}
}
return false;
}
/**
* Pops and shuts down excessive spare threads. Call only while
* holding lock. This is not guaranteed to eliminate all excess
* threads, only those suspended as spares, which are the ones
* unlikely to be needed in the future.
*/
private void trimSpares() {
int surplus = totalCountOf(workerCounts) - parallelism;
WaitQueueNode q;
while (surplus > 0 && (q = spareStack) != null) {
if (casSpareStack(q, null)) {
do {
updateRunningCount(1);
ForkJoinWorkerThread w = q.thread;
if (w != null && surplus > 0 &&
runningCountOf(workerCounts) > 0 && w.shutdown())
--surplus;
q.signal();
} while ((q = q.next) != null);
}
} }
} }
...@@ -1838,11 +1758,17 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1838,11 +1758,17 @@ public class ForkJoinPool extends AbstractExecutorService {
* Interface for extending managed parallelism for tasks running * Interface for extending managed parallelism for tasks running
* in {@link ForkJoinPool}s. * in {@link ForkJoinPool}s.
* *
* <p>A {@code ManagedBlocker} provides two methods. * <p>A {@code ManagedBlocker} provides two methods. Method
* Method {@code isReleasable} must return {@code true} if * {@code isReleasable} must return {@code true} if blocking is
* blocking is not necessary. Method {@code block} blocks the * not necessary. Method {@code block} blocks the current thread
* current thread if necessary (perhaps internally invoking * if necessary (perhaps internally invoking {@code isReleasable}
* {@code isReleasable} before actually blocking). * before actually blocking). The unusual methods in this API
* accommodate synchronizers that may, but don't usually, block
* for long periods. Similarly, they allow more efficient internal
* handling of cases in which additional workers may be, but
* usually are not, needed to ensure sufficient parallelism.
* Toward this end, implementations of method {@code isReleasable}
* must be amenable to repeated invocation.
* *
* <p>For example, here is a ManagedBlocker based on a * <p>For example, here is a ManagedBlocker based on a
* ReentrantLock: * ReentrantLock:
...@@ -1860,6 +1786,26 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1860,6 +1786,26 @@ public class ForkJoinPool extends AbstractExecutorService {
* return hasLock || (hasLock = lock.tryLock()); * return hasLock || (hasLock = lock.tryLock());
* } * }
* }}</pre> * }}</pre>
*
* <p>Here is a class that possibly blocks waiting for an
* item on a given queue:
* <pre> {@code
* class QueueTaker<E> implements ManagedBlocker {
* final BlockingQueue<E> queue;
* volatile E item = null;
* QueueTaker(BlockingQueue<E> q) { this.queue = q; }
* public boolean block() throws InterruptedException {
* if (item == null)
* item = queue.take();
* return true;
* }
* public boolean isReleasable() {
* return item != null || (item = queue.poll()) != null;
* }
* public E getItem() { // call after pool.managedBlock completes
* return item;
* }
* }}</pre>
*/ */
public static interface ManagedBlocker { public static interface ManagedBlocker {
/** /**
...@@ -1883,14 +1829,7 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1883,14 +1829,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* Blocks in accord with the given blocker. If the current thread * Blocks in accord with the given blocker. If the current thread
* is a {@link ForkJoinWorkerThread}, this method possibly * is a {@link ForkJoinWorkerThread}, this method possibly
* arranges for a spare thread to be activated if necessary to * arranges for a spare thread to be activated if necessary to
* ensure parallelism while the current thread is blocked. * ensure sufficient parallelism while the current thread is blocked.
*
* <p>If {@code maintainParallelism} is {@code true} and the pool
* supports it ({@link #getMaintainsParallelism}), this method
* attempts to maintain the pool's nominal parallelism. Otherwise
* it activates a thread only if necessary to avoid complete
* starvation. This option may be preferable when blockages use
* timeouts, or are almost always brief.
* *
* <p>If the caller is not a {@link ForkJoinTask}, this method is * <p>If the caller is not a {@link ForkJoinTask}, this method is
* behaviorally equivalent to * behaviorally equivalent to
...@@ -1904,33 +1843,18 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1904,33 +1843,18 @@ public class ForkJoinPool extends AbstractExecutorService {
* first be expanded to ensure parallelism, and later adjusted. * first be expanded to ensure parallelism, and later adjusted.
* *
* @param blocker the blocker * @param blocker the blocker
* @param maintainParallelism if {@code true} and supported by
* this pool, attempt to maintain the pool's nominal parallelism;
* otherwise activate a thread only if necessary to avoid
* complete starvation.
* @throws InterruptedException if blocker.block did so * @throws InterruptedException if blocker.block did so
*/ */
public static void managedBlock(ManagedBlocker blocker, public static void managedBlock(ManagedBlocker blocker)
boolean maintainParallelism)
throws InterruptedException { throws InterruptedException {
Thread t = Thread.currentThread(); Thread t = Thread.currentThread();
ForkJoinPool pool = ((t instanceof ForkJoinWorkerThread) ? if (t instanceof ForkJoinWorkerThread) {
((ForkJoinWorkerThread) t).pool : null); ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
if (!blocker.isReleasable()) { w.pool.awaitBlocker(blocker);
try { }
if (pool == null || else {
!pool.preBlock(blocker, maintainParallelism)) do {} while (!blocker.isReleasable() && !blocker.block());
awaitBlocker(blocker);
} finally {
if (pool != null)
pool.updateRunningCount(1);
}
} }
}
private static void awaitBlocker(ManagedBlocker blocker)
throws InterruptedException {
do {} while (!blocker.isReleasable() && !blocker.block());
} }
// AbstractExecutorService overrides. These rely on undocumented // AbstractExecutorService overrides. These rely on undocumented
...@@ -1948,32 +1872,18 @@ public class ForkJoinPool extends AbstractExecutorService { ...@@ -1948,32 +1872,18 @@ public class ForkJoinPool extends AbstractExecutorService {
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long eventCountOffset =
objectFieldOffset("eventCount", ForkJoinPool.class);
private static final long workerCountsOffset = private static final long workerCountsOffset =
objectFieldOffset("workerCounts", ForkJoinPool.class); objectFieldOffset("workerCounts", ForkJoinPool.class);
private static final long runControlOffset = private static final long runStateOffset =
objectFieldOffset("runControl", ForkJoinPool.class); objectFieldOffset("runState", ForkJoinPool.class);
private static final long syncStackOffset = private static final long eventCountOffset =
objectFieldOffset("syncStack",ForkJoinPool.class); objectFieldOffset("eventCount", ForkJoinPool.class);
private static final long spareStackOffset = private static final long eventWaitersOffset =
objectFieldOffset("spareStack", ForkJoinPool.class); objectFieldOffset("eventWaiters", ForkJoinPool.class);
private static final long stealCountOffset =
private boolean casEventCount(long cmp, long val) { objectFieldOffset("stealCount", ForkJoinPool.class);
return UNSAFE.compareAndSwapLong(this, eventCountOffset, cmp, val); private static final long spareWaitersOffset =
} objectFieldOffset("spareWaiters", ForkJoinPool.class);
private boolean casWorkerCounts(int cmp, int val) {
return UNSAFE.compareAndSwapInt(this, workerCountsOffset, cmp, val);
}
private boolean casRunControl(int cmp, int val) {
return UNSAFE.compareAndSwapInt(this, runControlOffset, cmp, val);
}
private boolean casSpareStack(WaitQueueNode cmp, WaitQueueNode val) {
return UNSAFE.compareAndSwapObject(this, spareStackOffset, cmp, val);
}
private boolean casBarrierStack(WaitQueueNode cmp, WaitQueueNode val) {
return UNSAFE.compareAndSwapObject(this, syncStackOffset, cmp, val);
}
private static long objectFieldOffset(String field, Class<?> klazz) { private static long objectFieldOffset(String field, Class<?> klazz) {
try { try {
......
...@@ -91,10 +91,7 @@ import java.util.WeakHashMap; ...@@ -91,10 +91,7 @@ import java.util.WeakHashMap;
* results of a task is {@link #join}, but there are several variants: * results of a task is {@link #join}, but there are several variants:
* The {@link Future#get} methods support interruptible and/or timed * The {@link Future#get} methods support interruptible and/or timed
* waits for completion and report results using {@code Future} * waits for completion and report results using {@code Future}
* conventions. Method {@link #helpJoin} enables callers to actively * conventions. Method {@link #invoke} is semantically
* execute other tasks while awaiting joins, which is sometimes more
* efficient but only applies when all subtasks are known to be
* strictly tree-structured. Method {@link #invoke} is semantically
* equivalent to {@code fork(); join()} but always attempts to begin * equivalent to {@code fork(); join()} but always attempts to begin
* execution in the current thread. The "<em>quiet</em>" forms of * execution in the current thread. The "<em>quiet</em>" forms of
* these methods do not extract results or report exceptions. These * these methods do not extract results or report exceptions. These
...@@ -130,7 +127,7 @@ import java.util.WeakHashMap; ...@@ -130,7 +127,7 @@ import java.util.WeakHashMap;
* ForkJoinTasks (as may be determined using method {@link * ForkJoinTasks (as may be determined using method {@link
* #inForkJoinPool}). Attempts to invoke them in other contexts * #inForkJoinPool}). Attempts to invoke them in other contexts
* result in exceptions or errors, possibly including * result in exceptions or errors, possibly including
* ClassCastException. * {@code ClassCastException}.
* *
* <p>Most base support methods are {@code final}, to prevent * <p>Most base support methods are {@code final}, to prevent
* overriding of implementations that are intrinsically tied to the * overriding of implementations that are intrinsically tied to the
...@@ -152,9 +149,8 @@ import java.util.WeakHashMap; ...@@ -152,9 +149,8 @@ import java.util.WeakHashMap;
* *
* <p>This class provides {@code adapt} methods for {@link Runnable} * <p>This class provides {@code adapt} methods for {@link Runnable}
* and {@link Callable}, that may be of use when mixing execution of * and {@link Callable}, that may be of use when mixing execution of
* {@code ForkJoinTasks} with other kinds of tasks. When all tasks * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
* are of this form, consider using a pool in * of this form, consider using a pool constructed in <em>asyncMode</em>.
* {@linkplain ForkJoinPool#setAsyncMode async mode}.
* *
* <p>ForkJoinTasks are {@code Serializable}, which enables them to be * <p>ForkJoinTasks are {@code Serializable}, which enables them to be
* used in extensions such as remote execution frameworks. It is * used in extensions such as remote execution frameworks. It is
...@@ -166,33 +162,43 @@ import java.util.WeakHashMap; ...@@ -166,33 +162,43 @@ import java.util.WeakHashMap;
*/ */
public abstract class ForkJoinTask<V> implements Future<V>, Serializable { public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/** /*
* Run control status bits packed into a single int to minimize * See the internal documentation of class ForkJoinPool for a
* footprint and to ensure atomicity (via CAS). Status is * general implementation overview. ForkJoinTasks are mainly
* initially zero, and takes on nonnegative values until * responsible for maintaining their "status" field amidst relays
* completed, upon which status holds COMPLETED. CANCELLED, or * to methods in ForkJoinWorkerThread and ForkJoinPool. The
* EXCEPTIONAL, which use the top 3 bits. Tasks undergoing * methods of this class are more-or-less layered into (1) basic
* blocking waits by other threads have SIGNAL_MASK bits set -- * status maintenance (2) execution and awaiting completion (3)
* bit 15 for external (nonFJ) waits, and the rest a count of * user-level methods that additionally report results. This is
* waiting FJ threads. (This representation relies on * sometimes hard to see because this file orders exported methods
* ForkJoinPool max thread limits). Completion of a stolen task * in a way that flows well in javadocs. In particular, most
* with SIGNAL_MASK bits set awakens waiter via notifyAll. Even * join mechanics are in method quietlyJoin, below.
* though suboptimal for some purposes, we use basic builtin */
* wait/notify to take advantage of "monitor inflation" in JVMs
* that we would otherwise need to emulate to avoid adding further /*
* per-task bookkeeping overhead. Note that bits 16-28 are * The status field holds run control status bits packed into a
* currently unused. Also value 0x80000000 is available as spare * single int to minimize footprint and to ensure atomicity (via
* completion value. * CAS). Status is initially zero, and takes on nonnegative
* values until completed, upon which status holds value
* NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking
* waits by other threads have the SIGNAL bit set. Completion of
* a stolen task with SIGNAL set awakens any waiters via
* notifyAll. Even though suboptimal for some purposes, we use
* basic builtin wait/notify to take advantage of "monitor
* inflation" in JVMs that we would otherwise need to emulate to
* avoid adding further per-task bookkeeping overhead. We want
* these monitors to be "fat", i.e., not use biasing or thin-lock
* techniques, so use some odd coding idioms that tend to avoid
* them.
*/ */
/** The run status of this task */
volatile int status; // accessed directly by pool and workers volatile int status; // accessed directly by pool and workers
static final int COMPLETION_MASK = 0xe0000000; private static final int NORMAL = -1;
static final int NORMAL = 0xe0000000; // == mask private static final int CANCELLED = -2;
static final int CANCELLED = 0xc0000000; private static final int EXCEPTIONAL = -3;
static final int EXCEPTIONAL = 0xa0000000; private static final int SIGNAL = 1;
static final int SIGNAL_MASK = 0x0000ffff;
static final int INTERNAL_SIGNAL_MASK = 0x00007fff;
static final int EXTERNAL_SIGNAL = 0x00008000; // top bit of low word
/** /**
* Table of exceptions thrown by tasks, to enable reporting by * Table of exceptions thrown by tasks, to enable reporting by
...@@ -206,176 +212,94 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -206,176 +212,94 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
Collections.synchronizedMap Collections.synchronizedMap
(new WeakHashMap<ForkJoinTask<?>, Throwable>()); (new WeakHashMap<ForkJoinTask<?>, Throwable>());
// within-package utilities // Maintaining completion status
/** /**
* Gets current worker thread, or null if not a worker thread. * Marks completion and wakes up threads waiting to join this task,
*/ * also clearing signal request bits.
static ForkJoinWorkerThread getWorker() {
Thread t = Thread.currentThread();
return ((t instanceof ForkJoinWorkerThread) ?
(ForkJoinWorkerThread) t : null);
}
final boolean casStatus(int cmp, int val) {
return UNSAFE.compareAndSwapInt(this, statusOffset, cmp, val);
}
/**
* Workaround for not being able to rethrow unchecked exceptions.
*/
static void rethrowException(Throwable ex) {
if (ex != null)
UNSAFE.throwException(ex);
}
// Setting completion status
/**
* Marks completion and wakes up threads waiting to join this task.
* *
* @param completion one of NORMAL, CANCELLED, EXCEPTIONAL * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
*/ */
final void setCompletion(int completion) { private void setCompletion(int completion) {
ForkJoinPool pool = getPool(); int s;
if (pool != null) { while ((s = status) >= 0) {
int s; // Clear signal bits while setting completion status if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
do {} while ((s = status) >= 0 && !casStatus(s, completion)); if (s != 0)
synchronized (this) { notifyAll(); }
if ((s & SIGNAL_MASK) != 0) { break;
if ((s &= INTERNAL_SIGNAL_MASK) != 0)
pool.updateRunningCount(s);
synchronized (this) { notifyAll(); }
} }
} }
else
externallySetCompletion(completion);
}
/**
* Version of setCompletion for non-FJ threads. Leaves signal
* bits for unblocked threads to adjust, and always notifies.
*/
private void externallySetCompletion(int completion) {
int s;
do {} while ((s = status) >= 0 &&
!casStatus(s, (s & SIGNAL_MASK) | completion));
synchronized (this) { notifyAll(); }
}
/**
* Sets status to indicate normal completion.
*/
final void setNormalCompletion() {
// Try typical fast case -- single CAS, no signal, not already done.
// Manually expand casStatus to improve chances of inlining it
if (!UNSAFE.compareAndSwapInt(this, statusOffset, 0, NORMAL))
setCompletion(NORMAL);
} }
// internal waiting and notification
/** /**
* Performs the actual monitor wait for awaitDone. * Records exception and sets exceptional completion.
*
* @return status on exit
*/ */
private void doAwaitDone() { private void setExceptionalCompletion(Throwable rex) {
// Minimize lock bias and in/de-flation effects by maximizing exceptionMap.put(this, rex);
// chances of waiting inside sync setCompletion(EXCEPTIONAL);
try {
while (status >= 0)
synchronized (this) { if (status >= 0) wait(); }
} catch (InterruptedException ie) {
onInterruptedWait();
}
} }
/** /**
* Performs the actual timed monitor wait for awaitDone. * Blocks a worker thread until completion. Called only by
* pool. Currently unused -- pool-based waits use timeout
* version below.
*/ */
private void doAwaitDone(long startTime, long nanos) { final void internalAwaitDone() {
synchronized (this) { int s; // the odd construction reduces lock bias effects
while ((s = status) >= 0) {
try { try {
while (status >= 0) { synchronized(this) {
long nt = nanos - (System.nanoTime() - startTime); if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
if (nt <= 0) wait();
break;
wait(nt / 1000000, (int) (nt % 1000000));
} }
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
onInterruptedWait(); cancelIfTerminating();
} }
} }
} }
// Awaiting completion
/** /**
* Sets status to indicate there is joiner, then waits for join, * Blocks a worker thread until completed or timed out. Called
* surrounded with pool notifications. * only by pool.
* *
* @return status upon exit * @return status on exit
*/ */
private int awaitDone(ForkJoinWorkerThread w, final int internalAwaitDone(long millis) {
boolean maintainParallelism) {
ForkJoinPool pool = (w == null) ? null : w.pool;
int s; int s;
while ((s = status) >= 0) { if ((s = status) >= 0) {
if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { try {
if (pool == null || !pool.preJoin(this, maintainParallelism)) synchronized(this) {
doAwaitDone(); if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
if (((s = status) & INTERNAL_SIGNAL_MASK) != 0) wait(millis, 0);
adjustPoolCountsOnUnblock(pool);
break;
}
}
return s;
}
/**
* Timed version of awaitDone
*
* @return status upon exit
*/
private int awaitDone(ForkJoinWorkerThread w, long nanos) {
ForkJoinPool pool = (w == null) ? null : w.pool;
int s;
while ((s = status) >= 0) {
if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) {
long startTime = System.nanoTime();
if (pool == null || !pool.preJoin(this, false))
doAwaitDone(startTime, nanos);
if ((s = status) >= 0) {
adjustPoolCountsOnCancelledWait(pool);
s = status;
} }
if (s < 0 && (s & INTERNAL_SIGNAL_MASK) != 0) } catch (InterruptedException ie) {
adjustPoolCountsOnUnblock(pool); cancelIfTerminating();
break;
} }
s = status;
} }
return s; return s;
} }
/** /**
* Notifies pool that thread is unblocked. Called by signalled * Blocks a non-worker-thread until completion.
* threads when woken by non-FJ threads (which is atypical).
*/ */
private void adjustPoolCountsOnUnblock(ForkJoinPool pool) { private void externalAwaitDone() {
int s; int s;
do {} while ((s = status) < 0 && !casStatus(s, s & COMPLETION_MASK)); while ((s = status) >= 0) {
if (pool != null && (s &= INTERNAL_SIGNAL_MASK) != 0) synchronized(this) {
pool.updateRunningCount(s); if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)){
} boolean interrupted = false;
while (status >= 0) {
/** try {
* Notifies pool to adjust counts on cancelled or timed out wait. wait();
*/ } catch (InterruptedException ie) {
private void adjustPoolCountsOnCancelledWait(ForkJoinPool pool) { interrupted = true;
if (pool != null) { }
int s; }
while ((s = status) >= 0 && (s & INTERNAL_SIGNAL_MASK) != 0) { if (interrupted)
if (casStatus(s, s - 1)) { Thread.currentThread().interrupt();
pool.updateRunningCount(1);
break; break;
} }
} }
...@@ -383,153 +307,19 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -383,153 +307,19 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
/** /**
* Handles interruptions during waits. * Unless done, calls exec and records status if completed, but
*/ * doesn't wait for completion otherwise. Primary execution method
private void onInterruptedWait() { * for ForkJoinWorkerThread.
ForkJoinWorkerThread w = getWorker();
if (w == null)
Thread.currentThread().interrupt(); // re-interrupt
else if (w.isTerminating())
cancelIgnoringExceptions();
// else if FJworker, ignore interrupt
}
// Recording and reporting exceptions
private void setDoneExceptionally(Throwable rex) {
exceptionMap.put(this, rex);
setCompletion(EXCEPTIONAL);
}
/**
* Throws the exception associated with status s.
*
* @throws the exception
*/
private void reportException(int s) {
if ((s &= COMPLETION_MASK) < NORMAL) {
if (s == CANCELLED)
throw new CancellationException();
else
rethrowException(exceptionMap.get(this));
}
}
/**
* Returns result or throws exception using j.u.c.Future conventions.
* Only call when {@code isDone} known to be true or thread known
* to be interrupted.
*/
private V reportFutureResult()
throws InterruptedException, ExecutionException {
if (Thread.interrupted())
throw new InterruptedException();
int s = status & COMPLETION_MASK;
if (s < NORMAL) {
Throwable ex;
if (s == CANCELLED)
throw new CancellationException();
if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
throw new ExecutionException(ex);
}
return getRawResult();
}
/**
* Returns result or throws exception using j.u.c.Future conventions
* with timeouts.
*/
private V reportTimedFutureResult()
throws InterruptedException, ExecutionException, TimeoutException {
if (Thread.interrupted())
throw new InterruptedException();
Throwable ex;
int s = status & COMPLETION_MASK;
if (s == NORMAL)
return getRawResult();
else if (s == CANCELLED)
throw new CancellationException();
else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
throw new ExecutionException(ex);
else
throw new TimeoutException();
}
// internal execution methods
/**
* Calls exec, recording completion, and rethrowing exception if
* encountered. Caller should normally check status before calling.
*
* @return true if completed normally
*/
private boolean tryExec() {
try { // try block must contain only call to exec
if (!exec())
return false;
} catch (Throwable rex) {
setDoneExceptionally(rex);
rethrowException(rex);
return false; // not reached
}
setNormalCompletion();
return true;
}
/**
* Main execution method used by worker threads. Invokes
* base computation unless already complete.
*/ */
final void quietlyExec() { final void quietlyExec() {
if (status >= 0) {
try {
if (!exec())
return;
} catch (Throwable rex) {
setDoneExceptionally(rex);
return;
}
setNormalCompletion();
}
}
/**
* Calls exec(), recording but not rethrowing exception.
* Caller should normally check status before calling.
*
* @return true if completed normally
*/
private boolean tryQuietlyInvoke() {
try { try {
if (!exec()) if (status < 0 || !exec())
return false; return;
} catch (Throwable rex) { } catch (Throwable rex) {
setDoneExceptionally(rex); setExceptionalCompletion(rex);
return false; return;
}
setNormalCompletion();
return true;
}
/**
* Cancels, ignoring any exceptions it throws.
*/
final void cancelIgnoringExceptions() {
try {
cancel(false);
} catch (Throwable ignore) {
} }
} setCompletion(NORMAL); // must be outside try block
/**
* Main implementation of helpJoin
*/
private int busyJoin(ForkJoinWorkerThread w) {
int s;
ForkJoinTask<?> t;
while ((s = status) >= 0 && (t = w.scanWhileJoining(this)) != null)
t.quietlyExec();
return (s >= 0) ? awaitDone(w, false) : s; // block if no work
} }
// public methods // public methods
...@@ -567,34 +357,41 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -567,34 +357,41 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* @return the computed result * @return the computed result
*/ */
public final V join() { public final V join() {
ForkJoinWorkerThread w = getWorker(); quietlyJoin();
if (w == null || status < 0 || !w.unpushTask(this) || !tryExec()) Throwable ex;
reportException(awaitDone(w, true)); if (status < NORMAL && (ex = getException()) != null)
UNSAFE.throwException(ex);
return getRawResult(); return getRawResult();
} }
/** /**
* Commences performing this task, awaits its completion if * Commences performing this task, awaits its completion if
* necessary, and return its result, or throws an (unchecked) * necessary, and returns its result, or throws an (unchecked)
* exception if the underlying computation did so. * {@code RuntimeException} or {@code Error} if the underlying
* computation did so.
* *
* @return the computed result * @return the computed result
*/ */
public final V invoke() { public final V invoke() {
if (status >= 0 && tryExec()) quietlyInvoke();
return getRawResult(); Throwable ex;
else if (status < NORMAL && (ex = getException()) != null)
return join(); UNSAFE.throwException(ex);
return getRawResult();
} }
/** /**
* Forks the given tasks, returning when {@code isDone} holds for * Forks the given tasks, returning when {@code isDone} holds for
* each task or an (unchecked) exception is encountered, in which * each task or an (unchecked) exception is encountered, in which
* case the exception is rethrown. If either task encounters an * case the exception is rethrown. If more than one task
* exception, the other one may be, but is not guaranteed to be, * encounters an exception, then this method throws any one of
* cancelled. If both tasks throw an exception, then this method * these exceptions. If any task encounters an exception, the
* throws one of them. The individual status of each task may be * other may be cancelled. However, the execution status of
* checked using {@link #getException()} and related methods. * individual tasks is not guaranteed upon exceptional return. The
* status of each task may be obtained using {@link
* #getException()} and related methods to check if they have been
* cancelled, completed normally or exceptionally, or left
* unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinTask} computations (as may be determined using method
...@@ -615,12 +412,14 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -615,12 +412,14 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/** /**
* Forks the given tasks, returning when {@code isDone} holds for * Forks the given tasks, returning when {@code isDone} holds for
* each task or an (unchecked) exception is encountered, in which * each task or an (unchecked) exception is encountered, in which
* case the exception is rethrown. If any task encounters an * case the exception is rethrown. If more than one task
* exception, others may be, but are not guaranteed to be, * encounters an exception, then this method throws any one of
* cancelled. If more than one task encounters an exception, then * these exceptions. If any task encounters an exception, others
* this method throws any one of these exceptions. The individual * may be cancelled. However, the execution status of individual
* status of each task may be checked using {@link #getException()} * tasks is not guaranteed upon exceptional return. The status of
* and related methods. * each task may be obtained using {@link #getException()} and
* related methods to check if they have been cancelled, completed
* normally or exceptionally, or left unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinTask} computations (as may be determined using method
...@@ -644,7 +443,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -644,7 +443,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
t.fork(); t.fork();
else { else {
t.quietlyInvoke(); t.quietlyInvoke();
if (ex == null) if (ex == null && t.status < NORMAL)
ex = t.getException(); ex = t.getException();
} }
} }
...@@ -655,26 +454,27 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -655,26 +454,27 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
t.cancel(false); t.cancel(false);
else { else {
t.quietlyJoin(); t.quietlyJoin();
if (ex == null) if (ex == null && t.status < NORMAL)
ex = t.getException(); ex = t.getException();
} }
} }
} }
if (ex != null) if (ex != null)
rethrowException(ex); UNSAFE.throwException(ex);
} }
/** /**
* Forks all tasks in the specified collection, returning when * Forks all tasks in the specified collection, returning when
* {@code isDone} holds for each task or an (unchecked) exception * {@code isDone} holds for each task or an (unchecked) exception
* is encountered. If any task encounters an exception, others * is encountered, in which case the exception is rethrown. If
* may be, but are not guaranteed to be, cancelled. If more than * more than one task encounters an exception, then this method
* one task encounters an exception, then this method throws any * throws any one of these exceptions. If any task encounters an
* one of these exceptions. The individual status of each task * exception, others may be cancelled. However, the execution
* may be checked using {@link #getException()} and related * status of individual tasks is not guaranteed upon exceptional
* methods. The behavior of this operation is undefined if the * return. The status of each task may be obtained using {@link
* specified collection is modified while the operation is in * #getException()} and related methods to check if they have been
* progress. * cancelled, completed normally or exceptionally, or left
* unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinTask} computations (as may be determined using method
...@@ -706,7 +506,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -706,7 +506,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
t.fork(); t.fork();
else { else {
t.quietlyInvoke(); t.quietlyInvoke();
if (ex == null) if (ex == null && t.status < NORMAL)
ex = t.getException(); ex = t.getException();
} }
} }
...@@ -717,13 +517,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -717,13 +517,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
t.cancel(false); t.cancel(false);
else { else {
t.quietlyJoin(); t.quietlyJoin();
if (ex == null) if (ex == null && t.status < NORMAL)
ex = t.getException(); ex = t.getException();
} }
} }
} }
if (ex != null) if (ex != null)
rethrowException(ex); UNSAFE.throwException(ex);
return tasks; return tasks;
} }
...@@ -753,7 +553,35 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -753,7 +553,35 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
*/ */
public boolean cancel(boolean mayInterruptIfRunning) { public boolean cancel(boolean mayInterruptIfRunning) {
setCompletion(CANCELLED); setCompletion(CANCELLED);
return (status & COMPLETION_MASK) == CANCELLED; return status == CANCELLED;
}
/**
* Cancels, ignoring any exceptions thrown by cancel. Used during
* worker and pool shutdown. Cancel is spec'ed not to throw any
* exceptions, but if it does anyway, we have no recourse during
* shutdown, so guard against this case.
*/
final void cancelIgnoringExceptions() {
try {
cancel(false);
} catch (Throwable ignore) {
}
}
/**
* Cancels if current thread is a terminating worker thread,
* ignoring any exceptions thrown by cancel.
*/
final void cancelIfTerminating() {
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
((ForkJoinWorkerThread) t).isTerminating()) {
try {
cancel(false);
} catch (Throwable ignore) {
}
}
} }
public final boolean isDone() { public final boolean isDone() {
...@@ -761,7 +589,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -761,7 +589,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
public final boolean isCancelled() { public final boolean isCancelled() {
return (status & COMPLETION_MASK) == CANCELLED; return status == CANCELLED;
} }
/** /**
...@@ -770,7 +598,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -770,7 +598,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* @return {@code true} if this task threw an exception or was cancelled * @return {@code true} if this task threw an exception or was cancelled
*/ */
public final boolean isCompletedAbnormally() { public final boolean isCompletedAbnormally() {
return (status & COMPLETION_MASK) < NORMAL; return status < NORMAL;
} }
/** /**
...@@ -781,7 +609,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -781,7 +609,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* exception and was not cancelled * exception and was not cancelled
*/ */
public final boolean isCompletedNormally() { public final boolean isCompletedNormally() {
return (status & COMPLETION_MASK) == NORMAL; return status == NORMAL;
} }
/** /**
...@@ -792,7 +620,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -792,7 +620,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* @return the exception, or {@code null} if none * @return the exception, or {@code null} if none
*/ */
public final Throwable getException() { public final Throwable getException() {
int s = status & COMPLETION_MASK; int s = status;
return ((s >= NORMAL) ? null : return ((s >= NORMAL) ? null :
(s == CANCELLED) ? new CancellationException() : (s == CANCELLED) ? new CancellationException() :
exceptionMap.get(this)); exceptionMap.get(this));
...@@ -813,20 +641,21 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -813,20 +641,21 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* thrown will be a {@code RuntimeException} with cause {@code ex}. * thrown will be a {@code RuntimeException} with cause {@code ex}.
*/ */
public void completeExceptionally(Throwable ex) { public void completeExceptionally(Throwable ex) {
setDoneExceptionally((ex instanceof RuntimeException) || setExceptionalCompletion((ex instanceof RuntimeException) ||
(ex instanceof Error) ? ex : (ex instanceof Error) ? ex :
new RuntimeException(ex)); new RuntimeException(ex));
} }
/** /**
* Completes this task, and if not already aborted or cancelled, * Completes this task, and if not already aborted or cancelled,
* returning a {@code null} result upon {@code join} and related * returning the given value as the result of subsequent
* operations. This method may be used to provide results for * invocations of {@code join} and related operations. This method
* asynchronous tasks, or to provide alternative handling for * may be used to provide results for asynchronous tasks, or to
* tasks that would not otherwise complete normally. Its use in * provide alternative handling for tasks that would not otherwise
* other situations is discouraged. This method is * complete normally. Its use in other situations is
* overridable, but overridden versions must invoke {@code super} * discouraged. This method is overridable, but overridden
* implementation to maintain guarantees. * versions must invoke {@code super} implementation to maintain
* guarantees.
* *
* @param value the result value for this task * @param value the result value for this task
*/ */
...@@ -834,97 +663,151 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -834,97 +663,151 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
try { try {
setRawResult(value); setRawResult(value);
} catch (Throwable rex) { } catch (Throwable rex) {
setDoneExceptionally(rex); setExceptionalCompletion(rex);
return; return;
} }
setNormalCompletion(); setCompletion(NORMAL);
} }
public final V get() throws InterruptedException, ExecutionException { public final V get() throws InterruptedException, ExecutionException {
ForkJoinWorkerThread w = getWorker(); quietlyJoin();
if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) if (Thread.interrupted())
awaitDone(w, true); throw new InterruptedException();
return reportFutureResult(); int s = status;
if (s < NORMAL) {
Throwable ex;
if (s == CANCELLED)
throw new CancellationException();
if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
throw new ExecutionException(ex);
}
return getRawResult();
} }
public final V get(long timeout, TimeUnit unit) public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException { throws InterruptedException, ExecutionException, TimeoutException {
Thread t = Thread.currentThread();
ForkJoinPool pool;
if (t instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
if (status >= 0 && w.unpushTask(this))
quietlyExec();
pool = w.pool;
}
else
pool = null;
/*
* Timed wait loop intermixes cases for FJ (pool != null) and
* non FJ threads. For FJ, decrement pool count but don't try
* for replacement; increment count on completion. For non-FJ,
* deal with interrupts. This is messy, but a little less so
* than is splitting the FJ and nonFJ cases.
*/
boolean interrupted = false;
boolean dec = false; // true if pool count decremented
long nanos = unit.toNanos(timeout); long nanos = unit.toNanos(timeout);
ForkJoinWorkerThread w = getWorker(); for (;;) {
if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) if (pool == null && Thread.interrupted()) {
awaitDone(w, nanos); interrupted = true;
return reportTimedFutureResult(); break;
} }
int s = status;
/** if (s < 0)
* Possibly executes other tasks until this task {@link #isDone is break;
* done}, then returns the result of the computation. This method if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)) {
* may be more efficient than {@code join}, but is only applicable long startTime = System.nanoTime();
* when there are no potential dependencies between continuation long nt; // wait time
* of the current task and that of any other task that might be while (status >= 0 &&
* executed while helping. (This usually holds for pure (nt = nanos - (System.nanoTime() - startTime)) > 0) {
* divide-and-conquer tasks). if (pool != null && !dec)
* dec = pool.tryDecrementRunningCount();
* <p>This method may be invoked only from within {@code else {
* ForkJoinTask} computations (as may be determined using method long ms = nt / 1000000;
* {@link #inForkJoinPool}). Attempts to invoke in other contexts int ns = (int) (nt % 1000000);
* result in exceptions or errors, possibly including {@code try {
* ClassCastException}. synchronized(this) {
* if (status >= 0)
* @return the computed result wait(ms, ns);
*/ }
public final V helpJoin() { } catch (InterruptedException ie) {
ForkJoinWorkerThread w = (ForkJoinWorkerThread) Thread.currentThread(); if (pool != null)
if (status < 0 || !w.unpushTask(this) || !tryExec()) cancelIfTerminating();
reportException(busyJoin(w)); else {
return getRawResult(); interrupted = true;
} break;
}
/** }
* Possibly executes other tasks until this task {@link #isDone is }
* done}. This method may be useful when processing collections }
* of tasks when some have been cancelled or otherwise known to break;
* have aborted. }
*
* <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code
* ClassCastException}.
*/
public final void quietlyHelpJoin() {
if (status >= 0) {
ForkJoinWorkerThread w =
(ForkJoinWorkerThread) Thread.currentThread();
if (!w.unpushTask(this) || !tryQuietlyInvoke())
busyJoin(w);
} }
if (pool != null && dec)
pool.incrementRunningCount();
if (interrupted)
throw new InterruptedException();
int es = status;
if (es != NORMAL) {
Throwable ex;
if (es == CANCELLED)
throw new CancellationException();
if (es == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
throw new ExecutionException(ex);
throw new TimeoutException();
}
return getRawResult();
} }
/** /**
* Joins this task, without returning its result or throwing an * Joins this task, without returning its result or throwing its
* exception. This method may be useful when processing * exception. This method may be useful when processing
* collections of tasks when some have been cancelled or otherwise * collections of tasks when some have been cancelled or otherwise
* known to have aborted. * known to have aborted.
*/ */
public final void quietlyJoin() { public final void quietlyJoin() {
if (status >= 0) { Thread t;
ForkJoinWorkerThread w = getWorker(); if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
if (w == null || !w.unpushTask(this) || !tryQuietlyInvoke()) ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
awaitDone(w, true); if (status >= 0) {
if (w.unpushTask(this)) {
boolean completed;
try {
completed = exec();
} catch (Throwable rex) {
setExceptionalCompletion(rex);
return;
}
if (completed) {
setCompletion(NORMAL);
return;
}
}
w.joinTask(this);
}
} }
else
externalAwaitDone();
} }
/** /**
* Commences performing this task and awaits its completion if * Commences performing this task and awaits its completion if
* necessary, without returning its result or throwing an * necessary, without returning its result or throwing its
* exception. This method may be useful when processing * exception.
* collections of tasks when some have been cancelled or otherwise
* known to have aborted.
*/ */
public final void quietlyInvoke() { public final void quietlyInvoke() {
if (status >= 0 && !tryQuietlyInvoke()) if (status >= 0) {
quietlyJoin(); boolean completed;
try {
completed = exec();
} catch (Throwable rex) {
setExceptionalCompletion(rex);
return;
}
if (completed)
setCompletion(NORMAL);
else
quietlyJoin();
}
} }
/** /**
...@@ -956,7 +839,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -956,7 +839,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* pre-constructed trees of subtasks in loops. * pre-constructed trees of subtasks in loops.
*/ */
public void reinitialize() { public void reinitialize() {
if ((status & COMPLETION_MASK) == EXCEPTIONAL) if (status == EXCEPTIONAL)
exceptionMap.remove(this); exceptionMap.remove(this);
status = 0; status = 0;
} }
...@@ -1246,7 +1129,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -1246,7 +1129,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
private static final long serialVersionUID = -7721805057305804111L; private static final long serialVersionUID = -7721805057305804111L;
/** /**
* Saves the state to a stream. * Saves the state to a stream (that is, serializes it).
* *
* @serialData the current run status and the exception thrown * @serialData the current run status and the exception thrown
* during execution, or {@code null} if none * during execution, or {@code null} if none
...@@ -1259,18 +1142,16 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { ...@@ -1259,18 +1142,16 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
/** /**
* Reconstitutes the instance from a stream. * Reconstitutes the instance from a stream (that is, deserializes it).
* *
* @param s the stream * @param s the stream
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException { throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject(); s.defaultReadObject();
status &= ~INTERNAL_SIGNAL_MASK; // clear internal signal counts
status |= EXTERNAL_SIGNAL; // conservatively set external signal
Object ex = s.readObject(); Object ex = s.readObject();
if (ex != null) if (ex != null)
setDoneExceptionally((Throwable) ex); setExceptionalCompletion((Throwable) ex);
} }
// Unsafe mechanics // Unsafe mechanics
......
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
package java.util.concurrent; package java.util.concurrent;
import java.util.Random;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.locks.LockSupport;
/** /**
* A thread managed by a {@link ForkJoinPool}. This class is * A thread managed by a {@link ForkJoinPool}. This class is
...@@ -52,46 +54,55 @@ import java.util.Collection; ...@@ -52,46 +54,55 @@ import java.util.Collection;
*/ */
public class ForkJoinWorkerThread extends Thread { public class ForkJoinWorkerThread extends Thread {
/* /*
* Algorithm overview: * Overview:
* *
* 1. Work-Stealing: Work-stealing queues are special forms of * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
* Deques that support only three of the four possible * ForkJoinTasks. This class includes bookkeeping in support of
* end-operations -- push, pop, and deq (aka steal), and only do * worker activation, suspension, and lifecycle control described
* so under the constraints that push and pop are called only from * in more detail in the internal documentation of class
* the owning thread, while deq may be called from other threads. * ForkJoinPool. And as described further below, this class also
* (If you are unfamiliar with them, you probably want to read * includes special-cased support for some ForkJoinTask
* Herlihy and Shavit's book "The Art of Multiprocessor * methods. But the main mechanics involve work-stealing:
* programming", chapter 16 describing these in more detail before *
* proceeding.) The main work-stealing queue design is roughly * Work-stealing queues are special forms of Deques that support
* similar to "Dynamic Circular Work-Stealing Deque" by David * only three of the four possible end-operations -- push, pop,
* Chase and Yossi Lev, SPAA 2005 * and deq (aka steal), under the further constraints that push
* (http://research.sun.com/scalable/pubs/index.html). The main * and pop are called only from the owning thread, while deq may
* difference ultimately stems from gc requirements that we null * be called from other threads. (If you are unfamiliar with
* out taken slots as soon as we can, to maintain as small a * them, you probably want to read Herlihy and Shavit's book "The
* footprint as possible even in programs generating huge numbers * Art of Multiprocessor programming", chapter 16 describing these
* of tasks. To accomplish this, we shift the CAS arbitrating pop * in more detail before proceeding.) The main work-stealing
* vs deq (steal) from being on the indices ("base" and "sp") to * queue design is roughly similar to those in the papers "Dynamic
* the slots themselves (mainly via method "casSlotNull()"). So, * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
* both a successful pop and deq mainly entail CAS'ing a non-null * (http://research.sun.com/scalable/pubs/index.html) and
* slot to null. Because we rely on CASes of references, we do * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
* not need tag bits on base or sp. They are simple ints as used * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
* in any circular array-based queue (see for example ArrayDeque). * The main differences ultimately stem from gc requirements that
* Updates to the indices must still be ordered in a way that * we null out taken slots as soon as we can, to maintain as small
* guarantees that (sp - base) > 0 means the queue is empty, but * a footprint as possible even in programs generating huge
* otherwise may err on the side of possibly making the queue * numbers of tasks. To accomplish this, we shift the CAS
* appear nonempty when a push, pop, or deq have not fully * arbitrating pop vs deq (steal) from being on the indices
* committed. Note that this means that the deq operation, * ("base" and "sp") to the slots themselves (mainly via method
* considered individually, is not wait-free. One thief cannot * "casSlotNull()"). So, both a successful pop and deq mainly
* successfully continue until another in-progress one (or, if * entail a CAS of a slot from non-null to null. Because we rely
* previously empty, a push) completes. However, in the * on CASes of references, we do not need tag bits on base or sp.
* aggregate, we ensure at least probabilistic * They are simple ints as used in any circular array-based queue
* non-blockingness. If an attempted steal fails, a thief always * (see for example ArrayDeque). Updates to the indices must
* chooses a different random victim target to try next. So, in * still be ordered in a way that guarantees that sp == base means
* order for one thief to progress, it suffices for any * the queue is empty, but otherwise may err on the side of
* in-progress deq or new push on any empty queue to complete. One * possibly making the queue appear nonempty when a push, pop, or
* reason this works well here is that apparently-nonempty often * deq have not fully committed. Note that this means that the deq
* means soon-to-be-stealable, which gives threads a chance to * operation, considered individually, is not wait-free. One thief
* activate if necessary before stealing (see below). * cannot successfully continue until another in-progress one (or,
* if previously empty, a push) completes. However, in the
* aggregate, we ensure at least probabilistic non-blockingness.
* If an attempted steal fails, a thief always chooses a different
* random victim target to try next. So, in order for one thief to
* progress, it suffices for any in-progress deq or new push on
* any empty queue to complete. One reason this works well here is
* that apparently-nonempty often means soon-to-be-stealable,
* which gives threads a chance to set activation status if
* necessary before stealing.
* *
* This approach also enables support for "async mode" where local * This approach also enables support for "async mode" where local
* task processing is in FIFO, not LIFO order; simply by using a * task processing is in FIFO, not LIFO order; simply by using a
...@@ -99,24 +110,54 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -99,24 +110,54 @@ public class ForkJoinWorkerThread extends Thread {
* by the ForkJoinPool). This allows use in message-passing * by the ForkJoinPool). This allows use in message-passing
* frameworks in which tasks are never joined. * frameworks in which tasks are never joined.
* *
* Efficient implementation of this approach currently relies on * When a worker would otherwise be blocked waiting to join a
* an uncomfortable amount of "Unsafe" mechanics. To maintain * task, it first tries a form of linear helping: Each worker
* records (in field currentSteal) the most recent task it stole
* from some other worker. Plus, it records (in field currentJoin)
* the task it is currently actively joining. Method joinTask uses
* these markers to try to find a worker to help (i.e., steal back
* a task from and execute it) that could hasten completion of the
* actively joined task. In essence, the joiner executes a task
* that would be on its own local deque had the to-be-joined task
* not been stolen. This may be seen as a conservative variant of
* the approach in Wagner & Calder "Leapfrogging: a portable
* technique for implementing efficient futures" SIGPLAN Notices,
* 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
* in that: (1) We only maintain dependency links across workers
* upon steals, rather than use per-task bookkeeping. This may
* require a linear scan of workers array to locate stealers, but
* usually doesn't because stealers leave hints (that may become
* stale/wrong) of where to locate them. This isolates cost to
* when it is needed, rather than adding to per-task overhead.
* (2) It is "shallow", ignoring nesting and potentially cyclic
* mutual steals. (3) It is intentionally racy: field currentJoin
* is updated only while actively joining, which means that we
* miss links in the chain during long-lived tasks, GC stalls etc
* (which is OK since blocking in such cases is usually a good
* idea). (4) We bound the number of attempts to find work (see
* MAX_HELP_DEPTH) and fall back to suspending the worker and if
* necessary replacing it with a spare (see
* ForkJoinPool.awaitJoin).
*
* Efficient implementation of these algorithms currently relies
* on an uncomfortable amount of "Unsafe" mechanics. To maintain
* correct orderings, reads and writes of variable base require * correct orderings, reads and writes of variable base require
* volatile ordering. Variable sp does not require volatile write * volatile ordering. Variable sp does not require volatile
* but needs cheaper store-ordering on writes. Because they are * writes but still needs store-ordering, which we accomplish by
* protected by volatile base reads, reads of the queue array and * pre-incrementing sp before filling the slot with an ordered
* its slots do not need volatile load semantics, but writes (in * store. (Pre-incrementing also enables backouts used in
* push) require store order and CASes (in pop and deq) require * joinTask.) Because they are protected by volatile base reads,
* (volatile) CAS semantics. (See "Idempotent work stealing" by * reads of the queue array and its slots by other threads do not
* Michael, Saraswat, and Vechev, PPoPP 2009 * need volatile load semantics, but writes (in push) require
* http://portal.acm.org/citation.cfm?id=1504186 for an algorithm * store order and CASes (in pop and deq) require (volatile) CAS
* with similar properties, but without support for nulling * semantics. (Michael, Saraswat, and Vechev's algorithm has
* slots.) Since these combinations aren't supported using * similar properties, but without support for nulling slots.)
* ordinary volatiles, the only way to accomplish these * Since these combinations aren't supported using ordinary
* efficiently is to use direct Unsafe calls. (Using external * volatiles, the only way to accomplish these efficiently is to
* AtomicIntegers and AtomicReferenceArrays for the indices and * use direct Unsafe calls. (Using external AtomicIntegers and
* array is significantly slower because of memory locality and * AtomicReferenceArrays for the indices and array is
* indirection effects.) * significantly slower because of memory locality and indirection
* effects.)
* *
* Further, performance on most platforms is very sensitive to * Further, performance on most platforms is very sensitive to
* placement and sizing of the (resizable) queue array. Even * placement and sizing of the (resizable) queue array. Even
...@@ -124,56 +165,45 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -124,56 +165,45 @@ public class ForkJoinWorkerThread extends Thread {
* initial size must be large enough to counteract cache * initial size must be large enough to counteract cache
* contention effects across multiple queues (especially in the * contention effects across multiple queues (especially in the
* presence of GC cardmarking). Also, to improve thread-locality, * presence of GC cardmarking). Also, to improve thread-locality,
* queues are currently initialized immediately after the thread * queues are initialized after starting. All together, these
* gets the initial signal to start processing tasks. However, * low-level implementation choices produce as much as a factor of
* all queue-related methods except pushTask are written in a way * 4 performance improvement compared to naive implementations,
* that allows them to instead be lazily allocated and/or disposed * and enable the processing of billions of tasks per second,
* of when empty. All together, these low-level implementation * sometimes at the expense of ugliness.
* choices produce as much as a factor of 4 performance */
* improvement compared to naive implementations, and enable the
* processing of billions of tasks per second, sometimes at the /**
* expense of ugliness. * Generator for initial random seeds for random victim
* * selection. This is used only to create initial seeds. Random
* 2. Run control: The primary run control is based on a global * steals use a cheaper xorshift generator per steal attempt. We
* counter (activeCount) held by the pool. It uses an algorithm * expect only rare contention on seedGenerator, so just use a
* similar to that in Herlihy and Shavit section 17.6 to cause * plain Random.
* threads to eventually block when all threads declare they are */
* inactive. For this to work, threads must be declared active private static final Random seedGenerator = new Random();
* when executing tasks, and before stealing a task. They must be
* inactive before blocking on the Pool Barrier (awaiting a new /**
* submission or other Pool event). In between, there is some free * The maximum stolen->joining link depth allowed in helpJoinTask.
* play which we take advantage of to avoid contention and rapid * Depths for legitimate chains are unbounded, but we use a fixed
* flickering of the global activeCount: If inactive, we activate * constant to avoid (otherwise unchecked) cycles and bound
* only if a victim queue appears to be nonempty (see above). * staleness of traversal parameters at the expense of sometimes
* Similarly, a thread tries to inactivate only after a full scan * blocking when we could be helping.
* of other threads. The net effect is that contention on
* activeCount is rarely a measurable performance issue. (There
* are also a few other cases where we scan for work rather than
* retry/block upon contention.)
*
* 3. Selection control. We maintain policy of always choosing to
* run local tasks rather than stealing, and always trying to
* steal tasks before trying to run a new submission. All steals
* are currently performed in randomly-chosen deq-order. It may be
* worthwhile to bias these with locality / anti-locality
* information, but doing this well probably requires more
* lower-level information from JVMs than currently provided.
*/ */
private static final int MAX_HELP_DEPTH = 8;
/** /**
* Capacity of work-stealing queue array upon initialization. * Capacity of work-stealing queue array upon initialization.
* Must be a power of two. Initial size must be at least 2, but is * Must be a power of two. Initial size must be at least 4, but is
* padded to minimize cache effects. * padded to minimize cache effects.
*/ */
private static final int INITIAL_QUEUE_CAPACITY = 1 << 13; private static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
/** /**
* Maximum work-stealing queue array size. Must be less than or * Maximum work-stealing queue array size. Must be less than or
* equal to 1 << 28 to ensure lack of index wraparound. (This * equal to 1 << (31 - width of array entry) to ensure lack of
* is less than usual bounds, because we need leftshift by 3 * index wraparound. The value is set in the static block
* to be in int range). * at the end of this file after obtaining width.
*/ */
private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 28; private static final int MAXIMUM_QUEUE_CAPACITY;
/** /**
* The pool this thread works in. Accessed directly by ForkJoinTask. * The pool this thread works in. Accessed directly by ForkJoinTask.
...@@ -182,65 +212,118 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -182,65 +212,118 @@ public class ForkJoinWorkerThread extends Thread {
/** /**
* The work-stealing queue array. Size must be a power of two. * The work-stealing queue array. Size must be a power of two.
* Initialized when thread starts, to improve memory locality. * Initialized in onStart, to improve memory locality.
*/ */
private ForkJoinTask<?>[] queue; private ForkJoinTask<?>[] queue;
/**
* Index (mod queue.length) of least valid queue slot, which is
* always the next position to steal from if nonempty.
*/
private volatile int base;
/** /**
* Index (mod queue.length) of next queue slot to push to or pop * Index (mod queue.length) of next queue slot to push to or pop
* from. It is written only by owner thread, via ordered store. * from. It is written only by owner thread, and accessed by other
* Both sp and base are allowed to wrap around on overflow, but * threads only after reading (volatile) base. Both sp and base
* (sp - base) still estimates size. * are allowed to wrap around on overflow, but (sp - base) still
* estimates size.
*/ */
private volatile int sp; private int sp;
/** /**
* Index (mod queue.length) of least valid queue slot, which is * The index of most recent stealer, used as a hint to avoid
* always the next position to steal from if nonempty. * traversal in method helpJoinTask. This is only a hint because a
* worker might have had multiple steals and this only holds one
* of them (usually the most current). Declared non-volatile,
* relying on other prevailing sync to keep reasonably current.
*/ */
private volatile int base; private int stealHint;
/** /**
* Activity status. When true, this worker is considered active. * Run state of this worker. In addition to the usual run levels,
* Must be false upon construction. It must be true when executing * tracks if this worker is suspended as a spare, and if it was
* tasks, and BEFORE stealing a task. It must be false before * killed (trimmed) while suspended. However, "active" status is
* calling pool.sync. * maintained separately and modified only in conjunction with
* CASes of the pool's runState (which are currently sadly
* manually inlined for performance.) Accessed directly by pool
* to simplify checks for normal (zero) status.
*/ */
private boolean active; volatile int runState;
private static final int TERMINATING = 0x01;
private static final int TERMINATED = 0x02;
private static final int SUSPENDED = 0x04; // inactive spare
private static final int TRIMMED = 0x08; // killed while suspended
/** /**
* Run state of this worker. Supports simple versions of the usual * Number of steals. Directly accessed (and reset) by
* shutdown/shutdownNow control. * pool.tryAccumulateStealCount when idle.
*/ */
private volatile int runState; int stealCount;
/** /**
* Seed for random number generator for choosing steal victims. * Seed for random number generator for choosing steal victims.
* Uses Marsaglia xorshift. Must be nonzero upon initialization. * Uses Marsaglia xorshift. Must be initialized as nonzero.
*/ */
private int seed; private int seed;
/** /**
* Number of steals, transferred to pool when idle * Activity status. When true, this worker is considered active.
* Accessed directly by pool. Must be false upon construction.
*/
boolean active;
/**
* True if use local fifo, not default lifo, for local polling.
* Shadows value from ForkJoinPool.
*/ */
private int stealCount; private final boolean locallyFifo;
/** /**
* Index of this worker in pool array. Set once by pool before * Index of this worker in pool array. Set once by pool before
* running, and accessed directly by pool during cleanup etc. * running, and accessed directly by pool to locate this worker in
* its workers array.
*/ */
int poolIndex; int poolIndex;
/** /**
* The last barrier event waited for. Accessed in pool callback * The last pool event waited for. Accessed only by pool in
* methods, but only by current thread. * callback methods invoked within this thread.
*/
int lastEventCount;
/**
* Encoded index and event count of next event waiter. Accessed
* only by ForkJoinPool for managing event waiters.
*/
volatile long nextWaiter;
/**
* Number of times this thread suspended as spare. Accessed only
* by pool.
*/
int spareCount;
/**
* Encoded index and count of next spare waiter. Accessed only
* by ForkJoinPool for managing spares.
*/ */
long lastEventCount; volatile int nextSpare;
/** /**
* True if use local fifo, not default lifo, for local polling * The task currently being joined, set only when actively trying
* to help other stealers in helpJoinTask. Written only by this
* thread, but read by others.
*/ */
private boolean locallyFifo; private volatile ForkJoinTask<?> currentJoin;
/**
* The task most recently stolen from another worker (or
* submission queue). Written only by this thread, but read by
* others.
*/
private volatile ForkJoinTask<?> currentSteal;
/** /**
* Creates a ForkJoinWorkerThread operating in the given pool. * Creates a ForkJoinWorkerThread operating in the given pool.
...@@ -249,13 +332,24 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -249,13 +332,24 @@ public class ForkJoinWorkerThread extends Thread {
* @throws NullPointerException if pool is null * @throws NullPointerException if pool is null
*/ */
protected ForkJoinWorkerThread(ForkJoinPool pool) { protected ForkJoinWorkerThread(ForkJoinPool pool) {
if (pool == null) throw new NullPointerException();
this.pool = pool; this.pool = pool;
// Note: poolIndex is set by pool during construction this.locallyFifo = pool.locallyFifo;
// Remaining initialization is deferred to onStart setDaemon(true);
// To avoid exposing construction details to subclasses,
// remaining initialization is in start() and onStart()
} }
// Public access methods /**
* Performs additional initialization and starts this thread.
*/
final void start(int poolIndex, UncaughtExceptionHandler ueh) {
this.poolIndex = poolIndex;
if (ueh != null)
setUncaughtExceptionHandler(ueh);
start();
}
// Public/protected methods
/** /**
* Returns the pool hosting this thread. * Returns the pool hosting this thread.
...@@ -280,81 +374,55 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -280,81 +374,55 @@ public class ForkJoinWorkerThread extends Thread {
} }
/** /**
* Establishes local first-in-first-out scheduling mode for forked * Initializes internal state after construction but before
* tasks that are never joined. * processing any tasks. If you override this method, you must
* * invoke @code{super.onStart()} at the beginning of the method.
* @param async if true, use locally FIFO scheduling * Initialization requires care: Most fields must have legal
* default values, to ensure that attempted accesses from other
* threads work correctly even before this thread starts
* processing tasks.
*/ */
void setAsyncMode(boolean async) { protected void onStart() {
locallyFifo = async; int rs = seedGenerator.nextInt();
} seed = rs == 0? 1 : rs; // seed must be nonzero
// Runstate management
// Runstate values. Order matters
private static final int RUNNING = 0;
private static final int SHUTDOWN = 1;
private static final int TERMINATING = 2;
private static final int TERMINATED = 3;
final boolean isShutdown() { return runState >= SHUTDOWN; }
final boolean isTerminating() { return runState >= TERMINATING; }
final boolean isTerminated() { return runState == TERMINATED; }
final boolean shutdown() { return transitionRunStateTo(SHUTDOWN); }
final boolean shutdownNow() { return transitionRunStateTo(TERMINATING); }
/** // Allocate name string and arrays in this thread
* Transitions to at least the given state. String pid = Integer.toString(pool.getPoolNumber());
* String wid = Integer.toString(poolIndex);
* @return {@code true} if not already at least at given state setName("ForkJoinPool-" + pid + "-worker-" + wid);
*/
private boolean transitionRunStateTo(int state) {
for (;;) {
int s = runState;
if (s >= state)
return false;
if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, state))
return true;
}
}
/** queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
* Tries to set status to active; fails on contention.
*/
private boolean tryActivate() {
if (!active) {
if (!pool.tryIncrementActiveCount())
return false;
active = true;
}
return true;
} }
/** /**
* Tries to set status to inactive; fails on contention. * Performs cleanup associated with termination of this worker
* thread. If you override this method, you must invoke
* {@code super.onTermination} at the end of the overridden method.
*
* @param exception the exception causing this thread to abort due
* to an unrecoverable error, or {@code null} if completed normally
*/ */
private boolean tryInactivate() { protected void onTermination(Throwable exception) {
if (active) { try {
if (!pool.tryDecrementActiveCount()) ForkJoinPool p = pool;
return false; if (active) {
active = false; int a; // inline p.tryDecrementActiveCount
active = false;
do {} while (!UNSAFE.compareAndSwapInt
(p, poolRunStateOffset, a = p.runState, a - 1));
}
cancelTasks();
setTerminated();
p.workerTerminated(this);
} 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);
} }
return true;
} }
/**
* Computes next value for random victim probe. Scans don't
* require a very high quality generator, but also not a crummy
* one. Marsaglia xor-shift is cheap and works well.
*/
private static int xorShift(int r) {
r ^= (r << 13);
r ^= (r >>> 17);
return r ^ (r << 5);
}
// Lifecycle methods
/** /**
* This method is required to be public, but should never be * This method is required to be public, but should never be
* called explicitly. It performs the main run loop to execute * called explicitly. It performs the main run loop to execute
...@@ -364,7 +432,6 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -364,7 +432,6 @@ public class ForkJoinWorkerThread extends Thread {
Throwable exception = null; Throwable exception = null;
try { try {
onStart(); onStart();
pool.sync(this); // await first pool event
mainLoop(); mainLoop();
} catch (Throwable ex) { } catch (Throwable ex) {
exception = ex; exception = ex;
...@@ -373,138 +440,150 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -373,138 +440,150 @@ public class ForkJoinWorkerThread extends Thread {
} }
} }
// helpers for run()
/** /**
* Executes tasks until shut down. * Finds and executes tasks, and checks status while running.
*/ */
private void mainLoop() { private void mainLoop() {
while (!isShutdown()) { boolean ran = false; // true if ran a task on last step
ForkJoinTask<?> t = pollTask(); ForkJoinPool p = pool;
if (t != null || (t = pollSubmission()) != null) for (;;) {
t.quietlyExec(); p.preStep(this, ran);
else if (tryInactivate()) if (runState != 0)
pool.sync(this); break;
ran = tryExecSteal() || tryExecSubmission();
} }
} }
/** /**
* Initializes internal state after construction but before * Tries to steal a task and execute it.
* processing any tasks. If you override this method, you must *
* invoke super.onStart() at the beginning of the method. * @return true if ran a task
* Initialization requires care: Most fields must have legal
* default values, to ensure that attempted accesses from other
* threads work correctly even before this thread starts
* processing tasks.
*/ */
protected void onStart() { private boolean tryExecSteal() {
// Allocate while starting to improve chances of thread-local ForkJoinTask<?> t;
// isolation if ((t = scan()) != null) {
queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; t.quietlyExec();
// Initial value of seed need not be especially random but UNSAFE.putOrderedObject(this, currentStealOffset, null);
// should differ across workers and must be nonzero if (sp != base)
int p = poolIndex + 1; execLocalTasks();
seed = p + (p << 8) + (p << 16) + (p << 24); // spread bits return true;
}
return false;
} }
/** /**
* Performs cleanup associated with termination of this worker * If a submission exists, try to activate and run it.
* thread. If you override this method, you must invoke
* {@code super.onTermination} at the end of the overridden method.
* *
* @param exception the exception causing this thread to abort due * @return true if ran a task
* to an unrecoverable error, or {@code null} if completed normally
*/ */
protected void onTermination(Throwable exception) { private boolean tryExecSubmission() {
// Execute remaining local tasks unless aborting or terminating ForkJoinPool p = pool;
while (exception == null && pool.isProcessingTasks() && base != sp) { // This loop is needed in case attempt to activate fails, in
try { // which case we only retry if there still appears to be a
ForkJoinTask<?> t = popTask(); // submission.
if (t != null) while (p.hasQueuedSubmissions()) {
ForkJoinTask<?> t; int a;
if (active || // inline p.tryIncrementActiveCount
(active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
a = p.runState, a + 1))) {
if ((t = p.pollSubmission()) != null) {
UNSAFE.putOrderedObject(this, currentStealOffset, t);
t.quietlyExec(); t.quietlyExec();
} catch (Throwable ex) { UNSAFE.putOrderedObject(this, currentStealOffset, null);
exception = ex; if (sp != base)
execLocalTasks();
return true;
}
} }
} }
// Cancel other tasks, transition status, notify pool, and return false;
// propagate exception to uncaught exception handler
try {
do {} while (!tryInactivate()); // ensure inactive
cancelTasks();
runState = TERMINATED;
pool.workerTerminated(this);
} catch (Throwable ex) { // Shouldn't ever happen
if (exception == null) // but if so, at least rethrown
exception = ex;
} finally {
if (exception != null)
ForkJoinTask.rethrowException(exception);
}
}
// Intrinsics-based support for queue operations.
private static long slotOffset(int i) {
return ((long) i << qShift) + qBase;
} }
/** /**
* Adds in store-order the given task at given slot of q to null. * Runs local tasks until queue is empty or shut down. Call only
* Caller must ensure q is non-null and index is in range. * while active.
*/ */
private static void setSlot(ForkJoinTask<?>[] q, int i, private void execLocalTasks() {
ForkJoinTask<?> t) { while (runState == 0) {
UNSAFE.putOrderedObject(q, slotOffset(i), t); ForkJoinTask<?> t = locallyFifo ? locallyDeqTask() : popTask();
if (t != null)
t.quietlyExec();
else if (sp == base)
break;
}
} }
/*
* Intrinsics-based atomic writes for queue slots. These are
* basically the same as methods in AtomicReferenceArray, but
* specialized for (1) ForkJoinTask elements (2) requirement that
* nullness and bounds checks have already been performed by
* callers and (3) effective offsets are known not to overflow
* from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't
* need corresponding version for reads: plain array reads are OK
* because they are protected by other volatile reads and are
* confirmed by CASes.
*
* Most uses don't actually call these methods, but instead contain
* inlined forms that enable more predictable optimization. We
* don't define the version of write used in pushTask at all, but
* instead inline there a store-fenced array slot write.
*/
/** /**
* CAS given slot of q to null. Caller must ensure q is non-null * CASes slot i of array q from t to null. Caller must ensure q is
* and index is in range. * non-null and index is in range.
*/ */
private static boolean casSlotNull(ForkJoinTask<?>[] q, int i, private static final boolean casSlotNull(ForkJoinTask<?>[] q, int i,
ForkJoinTask<?> t) { ForkJoinTask<?> t) {
return UNSAFE.compareAndSwapObject(q, slotOffset(i), t, null); return UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null);
} }
/** /**
* Sets sp in store-order. * Performs a volatile write of the given task at given slot of
* array q. Caller must ensure q is non-null and index is in
* range. This method is used only during resets and backouts.
*/ */
private void storeSp(int s) { private static final void writeSlot(ForkJoinTask<?>[] q, int i,
UNSAFE.putOrderedInt(this, spOffset, s); ForkJoinTask<?> t) {
UNSAFE.putObjectVolatile(q, (i << qShift) + qBase, t);
} }
// Main queue methods // queue methods
/** /**
* Pushes a task. Called only by current thread. * Pushes a task. Call only from this thread.
* *
* @param t the task. Caller must ensure non-null. * @param t the task. Caller must ensure non-null.
*/ */
final void pushTask(ForkJoinTask<?> t) { final void pushTask(ForkJoinTask<?> t) {
ForkJoinTask<?>[] q = queue; ForkJoinTask<?>[] q = queue;
int mask = q.length - 1; int mask = q.length - 1; // implicit assert q != null
int s = sp; int s = sp++; // ok to increment sp before slot write
setSlot(q, s & mask, t); UNSAFE.putOrderedObject(q, ((s & mask) << qShift) + qBase, t);
storeSp(++s); if ((s -= base) == 0)
if ((s -= base) == 1) pool.signalWork(); // was empty
pool.signalWork(); else if (s == mask)
else if (s >= mask) growQueue(); // is full
growQueue();
} }
/** /**
* Tries to take a task from the base of the queue, failing if * Tries to take a task from the base of the queue, failing if
* either empty or contended. * empty or contended. Note: Specializations of this code appear
* in locallyDeqTask and elsewhere.
* *
* @return a task, or null if none or contended * @return a task, or null if none or contended
*/ */
final ForkJoinTask<?> deqTask() { final ForkJoinTask<?> deqTask() {
ForkJoinTask<?> t; ForkJoinTask<?> t;
ForkJoinTask<?>[] q; ForkJoinTask<?>[] q;
int i; int b, i;
int b;
if (sp != (b = base) && if (sp != (b = base) &&
(q = queue) != null && // must read q after b (q = queue) != null && // must read q after b
(t = q[i = (q.length - 1) & b]) != null && (t = q[i = (q.length - 1) & b]) != null && base == b &&
casSlotNull(q, i, t)) { UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null)) {
base = b + 1; base = b + 1;
return t; return t;
} }
...@@ -512,19 +591,20 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -512,19 +591,20 @@ public class ForkJoinWorkerThread extends Thread {
} }
/** /**
* Tries to take a task from the base of own queue, activating if * Tries to take a task from the base of own queue. Assumes active
* necessary, failing only if empty. Called only by current thread. * status. Called only by this thread.
* *
* @return a task, or null if none * @return a task, or null if none
*/ */
final ForkJoinTask<?> locallyDeqTask() { final ForkJoinTask<?> locallyDeqTask() {
int b; ForkJoinTask<?>[] q = queue;
while (sp != (b = base)) { if (q != null) {
if (tryActivate()) { ForkJoinTask<?> t;
ForkJoinTask<?>[] q = queue; int b, i;
int i = (q.length - 1) & b; while (sp != (b = base)) {
ForkJoinTask<?> t = q[i]; if ((t = q[i = (q.length - 1) & b]) != null && base == b &&
if (t != null && casSlotNull(q, i, t)) { UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase,
t, null)) {
base = b + 1; base = b + 1;
return t; return t;
} }
...@@ -534,46 +614,50 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -534,46 +614,50 @@ public class ForkJoinWorkerThread extends Thread {
} }
/** /**
* Returns a popped task, or null if empty. Ensures active status * Returns a popped task, or null if empty. Assumes active status.
* if non-null. Called only by current thread. * Called only by this thread.
*/ */
final ForkJoinTask<?> popTask() { private ForkJoinTask<?> popTask() {
int s = sp; ForkJoinTask<?>[] q = queue;
while (s != base) { if (q != null) {
if (tryActivate()) { int s;
ForkJoinTask<?>[] q = queue; while ((s = sp) != base) {
int mask = q.length - 1; int i = (q.length - 1) & --s;
int i = (s - 1) & mask; long u = (i << qShift) + qBase; // raw offset
ForkJoinTask<?> t = q[i]; ForkJoinTask<?> t = q[i];
if (t == null || !casSlotNull(q, i, t)) if (t == null) // lost to stealer
break; break;
storeSp(s - 1); if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
return t; sp = s; // putOrderedInt may encourage more timely write
// UNSAFE.putOrderedInt(this, spOffset, s);
return t;
}
} }
} }
return null; return null;
} }
/** /**
* Specialized version of popTask to pop only if * Specialized version of popTask to pop only if topmost element
* topmost element is the given task. Called only * is the given task. Called only by this thread while active.
* by current thread while active.
* *
* @param t the task. Caller must ensure non-null. * @param t the task. Caller must ensure non-null.
*/ */
final boolean unpushTask(ForkJoinTask<?> t) { final boolean unpushTask(ForkJoinTask<?> t) {
int s;
ForkJoinTask<?>[] q = queue; ForkJoinTask<?>[] q = queue;
int mask = q.length - 1; if ((s = sp) != base && q != null &&
int s = sp - 1; UNSAFE.compareAndSwapObject
if (casSlotNull(q, s & mask, t)) { (q, (((q.length - 1) & --s) << qShift) + qBase, t, null)) {
storeSp(s); sp = s; // putOrderedInt may encourage more timely write
// UNSAFE.putOrderedInt(this, spOffset, s);
return true; return true;
} }
return false; return false;
} }
/** /**
* Returns next task or null if empty or contended * Returns next task, or null if empty or contended.
*/ */
final ForkJoinTask<?> peekTask() { final ForkJoinTask<?> peekTask() {
ForkJoinTask<?>[] q = queue; ForkJoinTask<?>[] q = queue;
...@@ -606,104 +690,209 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -606,104 +690,209 @@ public class ForkJoinWorkerThread extends Thread {
ForkJoinTask<?> t = oldQ[oldIndex]; ForkJoinTask<?> t = oldQ[oldIndex];
if (t != null && !casSlotNull(oldQ, oldIndex, t)) if (t != null && !casSlotNull(oldQ, oldIndex, t))
t = null; t = null;
setSlot(newQ, b & newMask, t); writeSlot(newQ, b & newMask, t);
} while (++b != bf); } while (++b != bf);
pool.signalWork(); pool.signalWork();
} }
/**
* Computes next value for random victim probe in scan(). Scans
* don't require a very high quality generator, but also not a
* crummy one. Marsaglia xor-shift is cheap and works well enough.
* Note: This is manually inlined in scan().
*/
private static final int xorShift(int r) {
r ^= r << 13;
r ^= r >>> 17;
return r ^ (r << 5);
}
/** /**
* Tries to steal a task from another worker. Starts at a random * Tries to steal a task from another worker. Starts at a random
* index of workers array, and probes workers until finding one * index of workers array, and probes workers until finding one
* with non-empty queue or finding that all are empty. It * with non-empty queue or finding that all are empty. It
* randomly selects the first n probes. If these are empty, it * randomly selects the first n probes. If these are empty, it
* resorts to a full circular traversal, which is necessary to * resorts to a circular sweep, which is necessary to accurately
* accurately set active status by caller. Also restarts if pool * set active status. (The circular sweep uses steps of
* events occurred since last scan, which forces refresh of * approximately half the array size plus 1, to avoid bias
* workers array, in case barrier was associated with resize. * stemming from leftmost packing of the array in ForkJoinPool.)
* *
* This method must be both fast and quiet -- usually avoiding * This method must be both fast and quiet -- usually avoiding
* memory accesses that could disrupt cache sharing etc other than * memory accesses that could disrupt cache sharing etc other than
* those needed to check for and take tasks. This accounts for, * those needed to check for and take tasks (or to activate if not
* among other things, updating random seed in place without * already active). This accounts for, among other things,
* storing it until exit. * updating random seed in place without storing it until exit.
* *
* @return a task, or null if none found * @return a task, or null if none found
*/ */
private ForkJoinTask<?> scan() { private ForkJoinTask<?> scan() {
ForkJoinTask<?> t = null; ForkJoinPool p = pool;
int r = seed; // extract once to keep scan quiet ForkJoinWorkerThread[] ws; // worker array
ForkJoinWorkerThread[] ws; // refreshed on outer loop int n; // upper bound of #workers
int mask; // must be power 2 minus 1 and > 0 if ((ws = p.workers) != null && (n = ws.length) > 1) {
outer:do { boolean canSteal = active; // shadow active status
if ((ws = pool.workers) != null && (mask = ws.length - 1) > 0) { int r = seed; // extract seed once
int idx = r; int mask = n - 1;
int probes = ~mask; // use random index while negative int j = -n; // loop counter
for (;;) { int k = r; // worker index, random if j < 0
r = xorShift(r); // update random seed for (;;) {
ForkJoinWorkerThread v = ws[mask & idx]; ForkJoinWorkerThread v = ws[k & mask];
if (v == null || v.sp == v.base) { r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // inline xorshift
if (probes <= mask) ForkJoinTask<?>[] q; ForkJoinTask<?> t; int b, a;
idx = (probes++ < 0) ? r : (idx + 1); if (v != null && (b = v.base) != v.sp &&
else (q = v.queue) != null) {
break; int i = (q.length - 1) & b;
long u = (i << qShift) + qBase; // raw offset
int pid = poolIndex;
if ((t = q[i]) != null) {
if (!canSteal && // inline p.tryIncrementActiveCount
UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
a = p.runState, a + 1))
canSteal = active = true;
if (canSteal && v.base == b++ &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
v.base = b;
v.stealHint = pid;
UNSAFE.putOrderedObject(this,
currentStealOffset, t);
seed = r;
++stealCount;
return t;
}
} }
else if (!tryActivate() || (t = v.deqTask()) == null) j = -n;
continue outer; // restart on contention k = r; // restart on contention
else
break outer;
} }
else if (++j <= 0)
k = r;
else if (j <= n)
k += (n >>> 1) | 1;
else
break;
} }
} while (pool.hasNewSyncEvent(this)); // retry on pool events }
seed = r; return null;
return t;
} }
// Run State management
// status check methods used mainly by ForkJoinPool
final boolean isRunning() { return runState == 0; }
final boolean isTerminating() { return (runState & TERMINATING) != 0; }
final boolean isTerminated() { return (runState & TERMINATED) != 0; }
final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
/** /**
* Gets and removes a local or stolen task. * Sets state to TERMINATING. Does NOT unpark or interrupt
* * to wake up if currently blocked. Callers must do so if desired.
* @return a task, if available
*/ */
final ForkJoinTask<?> pollTask() { final void shutdown() {
ForkJoinTask<?> t = locallyFifo ? locallyDeqTask() : popTask(); for (;;) {
if (t == null && (t = scan()) != null) int s = runState;
++stealCount; if ((s & (TERMINATING|TERMINATED)) != 0)
return t; break;
if ((s & SUSPENDED) != 0) { // kill and wakeup if suspended
if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
(s & ~SUSPENDED) |
(TRIMMED|TERMINATING)))
break;
}
else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
s | TERMINATING))
break;
}
} }
/** /**
* Gets a local task. * Sets state to TERMINATED. Called only by onTermination().
*
* @return a task, if available
*/ */
final ForkJoinTask<?> pollLocalTask() { private void setTerminated() {
return locallyFifo ? locallyDeqTask() : popTask(); int s;
do {} while (!UNSAFE.compareAndSwapInt(this, runStateOffset,
s = runState,
s | (TERMINATING|TERMINATED)));
} }
/** /**
* Returns a pool submission, if one exists, activating first. * If suspended, tries to set status to unsuspended.
* Does NOT wake up if blocked.
* *
* @return a submission, if available * @return true if successful
*/ */
private ForkJoinTask<?> pollSubmission() { final boolean tryUnsuspend() {
int s;
while (((s = runState) & SUSPENDED) != 0) {
if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
s & ~SUSPENDED))
return true;
}
return false;
}
/**
* Sets suspended status and blocks as spare until resumed
* or shutdown.
*/
final void suspendAsSpare() {
for (;;) { // set suspended unless terminating
int s = runState;
if ((s & TERMINATING) != 0) { // must kill
if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
s | (TRIMMED | TERMINATING)))
return;
}
else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
s | SUSPENDED))
break;
}
ForkJoinPool p = pool; ForkJoinPool p = pool;
while (p.hasQueuedSubmissions()) { p.pushSpare(this);
ForkJoinTask<?> t; while ((runState & SUSPENDED) != 0) {
if (tryActivate() && (t = p.pollSubmission()) != null) if (p.tryAccumulateStealCount(this)) {
return t; interrupted(); // clear/ignore interrupts
if ((runState & SUSPENDED) == 0)
break;
LockSupport.park(this);
}
} }
return null;
} }
// Methods accessed only by Pool // Misc support methods for ForkJoinPool
/**
* Returns an estimate of the number of tasks in the queue. Also
* used by ForkJoinTask.
*/
final int getQueueSize() {
int n; // external calls must read base first
return (n = -base + sp) <= 0 ? 0 : n;
}
/** /**
* Removes and cancels all tasks in queue. Can be called from any * Removes and cancels all tasks in queue. Can be called from any
* thread. * thread.
*/ */
final void cancelTasks() { final void cancelTasks() {
ForkJoinTask<?> t; ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
while (base != sp && (t = deqTask()) != null) if (cj != null) {
t.cancelIgnoringExceptions(); currentJoin = null;
cj.cancelIgnoringExceptions();
try {
this.interrupt(); // awaken wait
} catch (SecurityException ignore) {
}
}
ForkJoinTask<?> cs = currentSteal;
if (cs != null) {
currentSteal = null;
cs.cancelIgnoringExceptions();
}
while (base != sp) {
ForkJoinTask<?> t = deqTask();
if (t != null)
t.cancelIgnoringExceptions();
}
} }
/** /**
...@@ -713,87 +902,266 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -713,87 +902,266 @@ public class ForkJoinWorkerThread extends Thread {
*/ */
final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) { final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
int n = 0; int n = 0;
ForkJoinTask<?> t; while (base != sp) {
while (base != sp && (t = deqTask()) != null) { ForkJoinTask<?> t = deqTask();
c.add(t); if (t != null) {
++n; c.add(t);
++n;
}
} }
return n; return n;
} }
// Support methods for ForkJoinTask
/** /**
* Gets and clears steal count for accumulation by pool. Called * Gets and removes a local task.
* only when known to be idle (in pool.sync and termination). *
* @return a task, if available
*/ */
final int getAndClearStealCount() { final ForkJoinTask<?> pollLocalTask() {
int sc = stealCount; ForkJoinPool p = pool;
stealCount = 0; while (sp != base) {
return sc; int a; // inline p.tryIncrementActiveCount
if (active ||
(active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
a = p.runState, a + 1)))
return locallyFifo ? locallyDeqTask() : popTask();
}
return null;
} }
/** /**
* Returns {@code true} if at least one worker in the given array * Gets and removes a local or stolen task.
* appears to have at least one queued task.
* *
* @param ws array of workers * @return a task, if available
*/ */
static boolean hasQueuedTasks(ForkJoinWorkerThread[] ws) { final ForkJoinTask<?> pollTask() {
if (ws != null) { ForkJoinTask<?> t = pollLocalTask();
int len = ws.length; if (t == null) {
for (int j = 0; j < 2; ++j) { // need two passes for clean sweep t = scan();
for (int i = 0; i < len; ++i) { // cannot retain/track/help steal
ForkJoinWorkerThread w = ws[i]; UNSAFE.putOrderedObject(this, currentStealOffset, null);
if (w != null && w.sp != w.base)
return true;
}
}
} }
return false; return t;
} }
// Support methods for ForkJoinTask
/** /**
* Returns an estimate of the number of tasks in the queue. * Possibly runs some tasks and/or blocks, until task is done.
*
* @param joinMe the task to join
*/ */
final int getQueueSize() { final void joinTask(ForkJoinTask<?> joinMe) {
// suppress momentarily negative values // currentJoin only written by this thread; only need ordered store
return Math.max(0, sp - base); ForkJoinTask<?> prevJoin = currentJoin;
UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe);
if (sp != base)
localHelpJoinTask(joinMe);
if (joinMe.status >= 0)
pool.awaitJoin(joinMe, this);
UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin);
} }
/** /**
* Returns an estimate of the number of tasks, offset by a * Run tasks in local queue until given task is done.
* function of number of idle workers. *
* @param joinMe the task to join
*/ */
final int getEstimatedSurplusTaskCount() { private void localHelpJoinTask(ForkJoinTask<?> joinMe) {
// The halving approximates weighting idle vs non-idle workers int s;
return (sp - base) - (pool.getIdleThreadCount() >>> 1); ForkJoinTask<?>[] q;
while (joinMe.status >= 0 && (s = sp) != base && (q = queue) != null) {
int i = (q.length - 1) & --s;
long u = (i << qShift) + qBase; // raw offset
ForkJoinTask<?> t = q[i];
if (t == null) // lost to a stealer
break;
if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
/*
* This recheck (and similarly in helpJoinTask)
* handles cases where joinMe is independently
* cancelled or forced even though there is other work
* available. Back out of the pop by putting t back
* into slot before we commit by writing sp.
*/
if (joinMe.status < 0) {
UNSAFE.putObjectVolatile(q, u, t);
break;
}
sp = s;
// UNSAFE.putOrderedInt(this, spOffset, s);
t.quietlyExec();
}
}
} }
/** /**
* Scans, returning early if joinMe done. * Unless terminating, tries to locate and help perform tasks for
* a stealer of the given task, or in turn one of its stealers.
* Traces currentSteal->currentJoin links looking for a thread
* working on a descendant of the given task and with a non-empty
* queue to steal back and execute tasks from.
*
* The implementation is very branchy to cope with potential
* inconsistencies or loops encountering chains that are stale,
* unknown, or of length greater than MAX_HELP_DEPTH links. All
* of these cases are dealt with by just returning back to the
* caller, who is expected to retry if other join mechanisms also
* don't work out.
*
* @param joinMe the task to join
*/ */
final ForkJoinTask<?> scanWhileJoining(ForkJoinTask<?> joinMe) { final void helpJoinTask(ForkJoinTask<?> joinMe) {
ForkJoinTask<?> t = pollTask(); ForkJoinWorkerThread[] ws;
if (t != null && joinMe.status < 0 && sp == base) { int n;
pushTask(t); // unsteal if done and this task would be stealable if (joinMe.status < 0) // already done
t = null; return;
if ((runState & TERMINATING) != 0) { // cancel if shutting down
joinMe.cancelIgnoringExceptions();
return;
}
if ((ws = pool.workers) == null || (n = ws.length) <= 1)
return; // need at least 2 workers
ForkJoinTask<?> task = joinMe; // base of chain
ForkJoinWorkerThread thread = this; // thread with stolen task
for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
// Try to find v, the stealer of task, by first using hint
ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
if (v == null || v.currentSteal != task) {
for (int j = 0; ; ++j) { // search array
if (j < n) {
ForkJoinTask<?> vs;
if ((v = ws[j]) != null &&
(vs = v.currentSteal) != null) {
if (joinMe.status < 0 || task.status < 0)
return; // stale or done
if (vs == task) {
thread.stealHint = j;
break; // save hint for next time
}
}
}
else
return; // no stealer
}
}
for (;;) { // Try to help v, using specialized form of deqTask
if (joinMe.status < 0)
return;
int b = v.base;
ForkJoinTask<?>[] q = v.queue;
if (b == v.sp || q == null)
break;
int i = (q.length - 1) & b;
long u = (i << qShift) + qBase;
ForkJoinTask<?> t = q[i];
int pid = poolIndex;
ForkJoinTask<?> ps = currentSteal;
if (task.status < 0)
return; // stale or done
if (t != null && v.base == b++ &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
if (joinMe.status < 0) {
UNSAFE.putObjectVolatile(q, u, t);
return; // back out on cancel
}
v.base = b;
v.stealHint = pid;
UNSAFE.putOrderedObject(this, currentStealOffset, t);
t.quietlyExec();
UNSAFE.putOrderedObject(this, currentStealOffset, ps);
}
}
// Try to descend to find v's stealer
ForkJoinTask<?> next = v.currentJoin;
if (task.status < 0 || next == null || next == task ||
joinMe.status < 0)
return;
task = next;
thread = v;
} }
return t; }
/**
* Implements ForkJoinTask.getSurplusQueuedTaskCount().
* Returns an estimate of the number of tasks, offset by a
* function of number of idle workers.
*
* This method provides a cheap heuristic guide for task
* partitioning when programmers, frameworks, tools, or languages
* have little or no idea about task granularity. In essence by
* offering this method, we ask users only about tradeoffs in
* overhead vs expected throughput and its variance, rather than
* how finely to partition tasks.
*
* In a steady state strict (tree-structured) computation, each
* thread makes available for stealing enough tasks for other
* threads to remain active. Inductively, if all threads play by
* the same rules, each thread should make available only a
* constant number of tasks.
*
* The minimum useful constant is just 1. But using a value of 1
* would require immediate replenishment upon each steal to
* maintain enough tasks, which is infeasible. Further,
* partitionings/granularities of offered tasks should minimize
* steal rates, which in general means that threads nearer the top
* of computation tree should generate more than those nearer the
* bottom. In perfect steady state, each thread is at
* approximately the same level of computation tree. However,
* producing extra tasks amortizes the uncertainty of progress and
* diffusion assumptions.
*
* So, users will want to use values larger, but not much larger
* than 1 to both smooth over transient shortages and hedge
* against uneven progress; as traded off against the cost of
* extra task overhead. We leave the user to pick a threshold
* value to compare with the results of this call to guide
* decisions, but recommend values such as 3.
*
* When all threads are active, it is on average OK to estimate
* surplus strictly locally. In steady-state, if one thread is
* maintaining say 2 surplus tasks, then so are others. So we can
* just use estimated queue length (although note that (sp - base)
* can be an overestimate because of stealers lagging increments
* of base). However, this strategy alone leads to serious
* mis-estimates in some non-steady-state conditions (ramp-up,
* ramp-down, other stalls). We can detect many of these by
* further considering the number of "idle" threads, that are
* known to have zero queued tasks, so compensate by a factor of
* (#idle/#active) threads.
*/
final int getEstimatedSurplusTaskCount() {
return sp - base - pool.idlePerActive();
} }
/** /**
* Runs tasks until {@code pool.isQuiescent()}. * Runs tasks until {@code pool.isQuiescent()}.
*/ */
final void helpQuiescePool() { final void helpQuiescePool() {
ForkJoinTask<?> ps = currentSteal; // to restore below
for (;;) { for (;;) {
ForkJoinTask<?> t = pollTask(); ForkJoinTask<?> t = pollLocalTask();
if (t != null) if (t != null || (t = scan()) != null)
t.quietlyExec(); t.quietlyExec();
else if (tryInactivate() && pool.isQuiescent()) else {
break; ForkJoinPool p = pool;
int a; // to inline CASes
if (active) {
if (!UNSAFE.compareAndSwapInt
(p, poolRunStateOffset, a = p.runState, a - 1))
continue; // retry later
active = false; // inactivate
UNSAFE.putOrderedObject(this, currentStealOffset, ps);
}
if (p.isQuiescent()) {
active = true; // re-activate
do {} while (!UNSAFE.compareAndSwapInt
(p, poolRunStateOffset, a = p.runState, a+1));
return;
}
}
} }
do {} while (!tryActivate()); // re-activate on exit
} }
// Unsafe mechanics // Unsafe mechanics
...@@ -803,15 +1171,23 @@ public class ForkJoinWorkerThread extends Thread { ...@@ -803,15 +1171,23 @@ public class ForkJoinWorkerThread extends Thread {
objectFieldOffset("sp", ForkJoinWorkerThread.class); objectFieldOffset("sp", ForkJoinWorkerThread.class);
private static final long runStateOffset = private static final long runStateOffset =
objectFieldOffset("runState", ForkJoinWorkerThread.class); objectFieldOffset("runState", ForkJoinWorkerThread.class);
private static final long qBase; private static final long currentJoinOffset =
objectFieldOffset("currentJoin", ForkJoinWorkerThread.class);
private static final long currentStealOffset =
objectFieldOffset("currentSteal", ForkJoinWorkerThread.class);
private static final long qBase =
UNSAFE.arrayBaseOffset(ForkJoinTask[].class);
private static final long poolRunStateOffset = // to inline CAS
objectFieldOffset("runState", ForkJoinPool.class);
private static final int qShift; private static final int qShift;
static { static {
qBase = UNSAFE.arrayBaseOffset(ForkJoinTask[].class);
int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class); int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class);
if ((s & (s-1)) != 0) if ((s & (s-1)) != 0)
throw new Error("data type scale not a power of two"); throw new Error("data type scale not a power of two");
qShift = 31 - Integer.numberOfLeadingZeros(s); qShift = 31 - Integer.numberOfLeadingZeros(s);
MAXIMUM_QUEUE_CAPACITY = 1 << (31 - qShift);
} }
private static long objectFieldOffset(String field, Class<?> klazz) { private static long objectFieldOffset(String field, Class<?> klazz) {
......
...@@ -42,6 +42,7 @@ import java.util.Iterator; ...@@ -42,6 +42,7 @@ import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
/** /**
* An unbounded {@link TransferQueue} based on linked nodes. * An unbounded {@link TransferQueue} based on linked nodes.
* This queue orders elements FIFO (first-in-first-out) with respect * This queue orders elements FIFO (first-in-first-out) with respect
...@@ -233,24 +234,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -233,24 +234,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* additional GC bookkeeping ("write barriers") that are sometimes * additional GC bookkeeping ("write barriers") that are sometimes
* more costly than the writes themselves because of contention). * more costly than the writes themselves because of contention).
* *
* Removal of interior nodes (due to timed out or interrupted
* waits, or calls to remove(x) or Iterator.remove) can use a
* scheme roughly similar to that described in Scherer, Lea, and
* Scott's SynchronousQueue. Given a predecessor, we can unsplice
* any node except the (actual) tail of the queue. To avoid
* build-up of cancelled trailing nodes, upon a request to remove
* a trailing node, it is placed in field "cleanMe" to be
* unspliced upon the next call to unsplice any other node.
* Situations needing such mechanics are not common but do occur
* in practice; for example when an unbounded series of short
* timed calls to poll repeatedly time out but never otherwise
* fall off the list because of an untimed call to take at the
* front of the queue. Note that maintaining field cleanMe does
* not otherwise much impact garbage retention even if never
* cleared by some other call because the held node will
* eventually either directly or indirectly lead to a self-link
* once off the list.
*
* *** Overview of implementation *** * *** Overview of implementation ***
* *
* We use a threshold-based approach to updates, with a slack * We use a threshold-based approach to updates, with a slack
...@@ -266,15 +249,10 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -266,15 +249,10 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* per-thread one available, but even ThreadLocalRandom is too * per-thread one available, but even ThreadLocalRandom is too
* heavy for these purposes. * heavy for these purposes.
* *
* With such a small slack threshold value, it is rarely * With such a small slack threshold value, it is not worthwhile
* worthwhile to augment this with path short-circuiting; i.e., * to augment this with path short-circuiting (i.e., unsplicing
* unsplicing nodes between head and the first unmatched node, or * interior nodes) except in the case of cancellation/removal (see
* similarly for tail, rather than advancing head or tail * below).
* proper. However, it is used (in awaitMatch) immediately before
* a waiting thread starts to block, as a final bit of helping at
* a point when contention with others is extremely unlikely
* (since if other threads that could release it are operating,
* then the current thread wouldn't be blocking).
* *
* We allow both the head and tail fields to be null before any * We allow both the head and tail fields to be null before any
* nodes are enqueued; initializing upon first append. This * nodes are enqueued; initializing upon first append. This
...@@ -356,6 +334,70 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -356,6 +334,70 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* versa) compared to their predecessors receive additional * versa) compared to their predecessors receive additional
* chained spins, reflecting longer paths typically required to * chained spins, reflecting longer paths typically required to
* unblock threads during phase changes. * unblock threads during phase changes.
*
*
* ** Unlinking removed interior nodes **
*
* In addition to minimizing garbage retention via self-linking
* described above, we also unlink removed interior nodes. These
* may arise due to timed out or interrupted waits, or calls to
* remove(x) or Iterator.remove. Normally, given a node that was
* at one time known to be the predecessor of some node s that is
* to be removed, we can unsplice s by CASing the next field of
* its predecessor if it still points to s (otherwise s must
* already have been removed or is now offlist). But there are two
* situations in which we cannot guarantee to make node s
* unreachable in this way: (1) If s is the trailing node of list
* (i.e., with null next), then it is pinned as the target node
* for appends, so can only be removed later after other nodes are
* appended. (2) We cannot necessarily unlink s given a
* predecessor node that is matched (including the case of being
* cancelled): the predecessor may already be unspliced, in which
* case some previous reachable node may still point to s.
* (For further explanation see Herlihy & Shavit "The Art of
* Multiprocessor Programming" chapter 9). Although, in both
* cases, we can rule out the need for further action if either s
* or its predecessor are (or can be made to be) at, or fall off
* from, the head of list.
*
* Without taking these into account, it would be possible for an
* unbounded number of supposedly removed nodes to remain
* reachable. Situations leading to such buildup are uncommon but
* can occur in practice; for example when a series of short timed
* calls to poll repeatedly time out but never otherwise fall off
* the list because of an untimed call to take at the front of the
* queue.
*
* When these cases arise, rather than always retraversing the
* entire list to find an actual predecessor to unlink (which
* won't help for case (1) anyway), we record a conservative
* estimate of possible unsplice failures (in "sweepVotes").
* We trigger a full sweep when the estimate exceeds a threshold
* ("SWEEP_THRESHOLD") indicating the maximum number of estimated
* removal failures to tolerate before sweeping through, unlinking
* cancelled nodes that were not unlinked upon initial removal.
* We perform sweeps by the thread hitting threshold (rather than
* background threads or by spreading work to other threads)
* because in the main contexts in which removal occurs, the
* caller is already timed-out, cancelled, or performing a
* potentially O(n) operation (e.g. remove(x)), none of which are
* time-critical enough to warrant the overhead that alternatives
* would impose on other threads.
*
* Because the sweepVotes estimate is conservative, and because
* nodes become unlinked "naturally" as they fall off the head of
* the queue, and because we allow votes to accumulate even while
* sweeps are in progress, there are typically significantly fewer
* such nodes than estimated. Choice of a threshold value
* balances the likelihood of wasted effort and contention, versus
* providing a worst-case bound on retention of interior nodes in
* quiescent queues. The value defined below was chosen
* empirically to balance these under various timeout scenarios.
*
* Note that we cannot self-link unlinked interior nodes during
* sweeps. However, the associated garbage chains terminate when
* some successor ultimately falls off the head of the list and is
* self-linked.
*/ */
/** True if on multiprocessor */ /** True if on multiprocessor */
...@@ -381,12 +423,20 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -381,12 +423,20 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
*/ */
private static final int CHAINED_SPINS = FRONT_SPINS >>> 1; private static final int CHAINED_SPINS = FRONT_SPINS >>> 1;
/**
* The maximum number of estimated removal failures (sweepVotes)
* to tolerate before sweeping through the queue unlinking
* cancelled nodes that were not unlinked upon initial
* removal. See above for explanation. The value must be at least
* two to avoid useless sweeps when removing trailing nodes.
*/
static final int SWEEP_THRESHOLD = 32;
/** /**
* Queue nodes. Uses Object, not E, for items to allow forgetting * Queue nodes. Uses Object, not E, for items to allow forgetting
* them after use. Relies heavily on Unsafe mechanics to minimize * them after use. Relies heavily on Unsafe mechanics to minimize
* unnecessary ordering constraints: Writes that intrinsically * unnecessary ordering constraints: Writes that are intrinsically
* precede or follow CASes use simple relaxed forms. Other * ordered wrt other accesses or CASes use simple relaxed forms.
* cleanups use releasing/lazy writes.
*/ */
static final class Node { static final class Node {
final boolean isData; // false if this is a request node final boolean isData; // false if this is a request node
...@@ -400,13 +450,13 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -400,13 +450,13 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
final boolean casItem(Object cmp, Object val) { final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class; // assert cmp == null || cmp.getClass() != Node.class;
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
} }
/** /**
* Creates a new node. Uses relaxed write because item can only * Constructs a new node. Uses relaxed write because item can
* be seen if followed by CAS. * only be seen after publication via casNext.
*/ */
Node(Object item, boolean isData) { Node(Object item, boolean isData) {
UNSAFE.putObject(this, itemOffset, item); // relaxed write UNSAFE.putObject(this, itemOffset, item); // relaxed write
...@@ -422,13 +472,17 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -422,13 +472,17 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
/** /**
* Sets item to self (using a releasing/lazy write) and waiter * Sets item to self and waiter to null, to avoid garbage
* to null, to avoid garbage retention after extracting or * retention after matching or cancelling. Uses relaxed writes
* cancelling. * because order is already constrained in the only calling
* contexts: item is forgotten only after volatile/atomic
* mechanics that extract items. Similarly, clearing waiter
* follows either CAS or return from park (if ever parked;
* else we don't care).
*/ */
final void forgetContents() { final void forgetContents() {
UNSAFE.putOrderedObject(this, itemOffset, this); UNSAFE.putObject(this, itemOffset, this);
UNSAFE.putOrderedObject(this, waiterOffset, null); UNSAFE.putObject(this, waiterOffset, null);
} }
/** /**
...@@ -462,7 +516,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -462,7 +516,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* Tries to artificially match a data node -- used by remove. * Tries to artificially match a data node -- used by remove.
*/ */
final boolean tryMatchData() { final boolean tryMatchData() {
// assert isData; // assert isData;
Object x = item; Object x = item;
if (x != null && x != this && casItem(x, null)) { if (x != null && x != this && casItem(x, null)) {
LockSupport.unpark(waiter); LockSupport.unpark(waiter);
...@@ -486,12 +540,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -486,12 +540,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
/** head of the queue; null until first enqueue */ /** head of the queue; null until first enqueue */
transient volatile Node head; transient volatile Node head;
/** predecessor of dangling unspliceable node */
private transient volatile Node cleanMe; // decl here reduces contention
/** tail of the queue; null until first append */ /** tail of the queue; null until first append */
private transient volatile Node tail; private transient volatile Node tail;
/** The number of apparent failures to unsplice removed nodes */
private transient volatile int sweepVotes;
// CAS methods for fields // CAS methods for fields
private boolean casTail(Node cmp, Node val) { private boolean casTail(Node cmp, Node val) {
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
...@@ -501,8 +555,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -501,8 +555,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
} }
private boolean casCleanMe(Node cmp, Node val) { private boolean casSweepVotes(int cmp, int val) {
return UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val); return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
} }
/* /*
...@@ -515,7 +569,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -515,7 +569,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <E> E cast(Object item) { static <E> E cast(Object item) {
// assert item == null || item.getClass() != Node.class; // assert item == null || item.getClass() != Node.class;
return (E) item; return (E) item;
} }
...@@ -544,10 +598,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -544,10 +598,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
break; break;
if (p.casItem(item, e)) { // match if (p.casItem(item, e)) { // match
for (Node q = p; q != h;) { for (Node q = p; q != h;) {
Node n = q.next; // update head by 2 Node n = q.next; // update by 2 unless singleton
if (n != null) // unless singleton if (head == h && casHead(h, n == null? q : n)) {
q = n;
if (head == h && casHead(h, q)) {
h.forgetNext(); h.forgetNext();
break; break;
} // advance and retry } // advance and retry
...@@ -632,12 +684,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -632,12 +684,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
for (;;) { for (;;) {
Object item = s.item; Object item = s.item;
if (item != e) { // matched if (item != e) { // matched
// assert item != s; // assert item != s;
s.forgetContents(); // avoid garbage s.forgetContents(); // avoid garbage
return this.<E>cast(item); return this.<E>cast(item);
} }
if ((w.isInterrupted() || (timed && nanos <= 0)) && if ((w.isInterrupted() || (timed && nanos <= 0)) &&
s.casItem(e, s)) { // cancel s.casItem(e, s)) { // cancel
unsplice(pred, s); unsplice(pred, s);
return e; return e;
} }
...@@ -647,9 +699,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -647,9 +699,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
randomYields = ThreadLocalRandom.current(); randomYields = ThreadLocalRandom.current();
} }
else if (spins > 0) { // spin else if (spins > 0) { // spin
if (--spins == 0) --spins;
shortenHeadPath(); // reduce slack before blocking if (randomYields.nextInt(CHAINED_SPINS) == 0)
else if (randomYields.nextInt(CHAINED_SPINS) == 0)
Thread.yield(); // occasionally yield Thread.yield(); // occasionally yield
} }
else if (s.waiter == null) { else if (s.waiter == null) {
...@@ -663,8 +714,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -663,8 +714,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
else { else {
LockSupport.park(this); LockSupport.park(this);
s.waiter = null;
spins = -1; // spin if front upon wakeup
} }
} }
} }
...@@ -685,27 +734,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -685,27 +734,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
return 0; return 0;
} }
/**
* Tries (once) to unsplice nodes between head and first unmatched
* or trailing node; failing on contention.
*/
private void shortenHeadPath() {
Node h, hn, p, q;
if ((p = h = head) != null && h.isMatched() &&
(q = hn = h.next) != null) {
Node n;
while ((n = q.next) != q) {
if (n == null || !q.isMatched()) {
if (hn != q && h.next == hn)
h.casNext(hn, q);
break;
}
p = q;
q = n;
}
}
}
/* -------------- Traversal methods -------------- */ /* -------------- Traversal methods -------------- */
/** /**
...@@ -818,7 +846,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -818,7 +846,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
public final void remove() { public final void remove() {
Node p = lastRet; Node p = lastRet;
if (p == null) throw new IllegalStateException(); if (p == null) throw new IllegalStateException();
findAndRemoveDataNode(lastPred, p); if (p.tryMatchData())
unsplice(lastPred, p);
} }
} }
...@@ -828,99 +857,68 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -828,99 +857,68 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* Unsplices (now or later) the given deleted/cancelled node with * Unsplices (now or later) the given deleted/cancelled node with
* the given predecessor. * the given predecessor.
* *
* @param pred predecessor of node to be unspliced * @param pred a node that was at one time known to be the
* predecessor of s, or null or s itself if s is/was at head
* @param s the node to be unspliced * @param s the node to be unspliced
*/ */
private void unsplice(Node pred, Node s) { final void unsplice(Node pred, Node s) {
s.forgetContents(); // clear unneeded fields s.forgetContents(); // forget unneeded fields
/* /*
* At any given time, exactly one node on list cannot be * See above for rationale. Briefly: if pred still points to
* unlinked -- the last inserted node. To accommodate this, if * s, try to unlink s. If s cannot be unlinked, because it is
* we cannot unlink s, we save its predecessor as "cleanMe", * trailing node or pred might be unlinked, and neither pred
* processing the previously saved version first. Because only * nor s are head or offlist, add to sweepVotes, and if enough
* one node in the list can have a null next, at least one of * votes have accumulated, sweep.
* node s or the node previously saved can always be
* processed, so this always terminates.
*/ */
if (pred != null && pred != s) { if (pred != null && pred != s && pred.next == s) {
while (pred.next == s) { Node n = s.next;
Node oldpred = (cleanMe == null) ? null : reclean(); if (n == null ||
Node n = s.next; (n != s && pred.casNext(s, n) && pred.isMatched())) {
if (n != null) { for (;;) { // check if at, or could be, head
if (n != s) Node h = head;
pred.casNext(s, n); if (h == pred || h == s || h == null)
break; return; // at head or list empty
if (!h.isMatched())
break;
Node hn = h.next;
if (hn == null)
return; // now empty
if (hn != h && casHead(h, hn))
h.forgetNext(); // advance head
} }
if (oldpred == pred || // Already saved if (pred.next != pred && s.next != s) { // recheck if offlist
((oldpred == null || oldpred.next == s) && for (;;) { // sweep now if enough votes
casCleanMe(oldpred, pred))) { int v = sweepVotes;
break; if (v < SWEEP_THRESHOLD) {
if (casSweepVotes(v, v + 1))
break;
}
else if (casSweepVotes(v, 0)) {
sweep();
break;
}
}
} }
} }
} }
} }
/** /**
* Tries to unsplice the deleted/cancelled node held in cleanMe * Unlinks matched (typically cancelled) nodes encountered in a
* that was previously uncleanable because it was at tail. * traversal from head.
*
* @return current cleanMe node (or null)
*/ */
private Node reclean() { private void sweep() {
/* for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
* cleanMe is, or at one time was, predecessor of a cancelled if (!s.isMatched())
* node s that was the tail so could not be unspliced. If it // Unmatched nodes are never self-linked
* is no longer the tail, try to unsplice if necessary and p = s;
* make cleanMe slot available. This differs from similar else if ((n = s.next) == null) // trailing node is pinned
* code in unsplice() because we must check that pred still
* points to a matched node that can be unspliced -- if not,
* we can (must) clear cleanMe without unsplicing. This can
* loop only due to contention.
*/
Node pred;
while ((pred = cleanMe) != null) {
Node s = pred.next;
Node n;
if (s == null || s == pred || !s.isMatched())
casCleanMe(pred, null); // already gone
else if ((n = s.next) != null) {
if (n != s)
pred.casNext(s, n);
casCleanMe(pred, null);
}
else
break; break;
} else if (s == n) // stale
return pred; // No need to also check for p == s, since that implies s == n
} p = head;
else
/** p.casNext(s, n);
* Main implementation of Iterator.remove(). Finds
* and unsplices the given data node.
*
* @param possiblePred possible predecessor of s
* @param s the node to remove
*/
final void findAndRemoveDataNode(Node possiblePred, Node s) {
// assert s.isData;
if (s.tryMatchData()) {
if (possiblePred != null && possiblePred.next == s)
unsplice(possiblePred, s); // was actual predecessor
else {
for (Node pred = null, p = head; p != null; ) {
if (p == s) {
unsplice(pred, p);
break;
}
if (p.isUnmatchedRequest())
break;
pred = p;
if ((p = p.next) == pred) { // stale
pred = null;
p = head;
}
}
}
} }
} }
...@@ -1158,7 +1156,11 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -1158,7 +1156,11 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* @return {@code true} if this queue contains no elements * @return {@code true} if this queue contains no elements
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return firstOfMode(true) == null; for (Node p = head; p != null; p = succ(p)) {
if (!p.isMatched())
return !p.isData;
}
return true;
} }
public boolean hasWaitingConsumer() { public boolean hasWaitingConsumer() {
...@@ -1252,8 +1254,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -1252,8 +1254,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class);
private static final long tailOffset = private static final long tailOffset =
objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class);
private static final long cleanMeOffset = private static final long sweepVotesOffset =
objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class); objectFieldOffset(UNSAFE, "sweepVotes", LinkedTransferQueue.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE, static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) { String field, Class<?> klazz) {
...@@ -1266,5 +1268,4 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -1266,5 +1268,4 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
throw error; throw error;
} }
} }
} }
...@@ -898,7 +898,7 @@ public class Phaser { ...@@ -898,7 +898,7 @@ public class Phaser {
boolean doWait() { boolean doWait() {
if (thread != null) { if (thread != null) {
try { try {
ForkJoinPool.managedBlock(this, false); ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
} }
} }
......
...@@ -206,7 +206,7 @@ public final class Integrate { ...@@ -206,7 +206,7 @@ public final class Integrate {
q.fork(); q.fork();
ar = recEval(c, r, fc, fr, ar); ar = recEval(c, r, fc, fr, ar);
if (!q.tryUnfork()) { if (!q.tryUnfork()) {
q.quietlyHelpJoin(); q.quietlyJoin();
return ar + q.area; return ar + q.area;
} }
return ar + recEval(l, c, fl, fc, al); return ar + recEval(l, c, fl, fc, al);
...@@ -254,7 +254,7 @@ public final class Integrate { ...@@ -254,7 +254,7 @@ public final class Integrate {
(q = new DQuad(l, c, al)).fork(); (q = new DQuad(l, c, al)).fork();
ar = recEval(c, r, fc, fr, ar); ar = recEval(c, r, fc, fr, ar);
if (q != null && !q.tryUnfork()) { if (q != null && !q.tryUnfork()) {
q.quietlyHelpJoin(); q.quietlyJoin();
return ar + q.area; return ar + q.area;
} }
return ar + recEval(l, c, fl, fc, al); return ar + recEval(l, c, fl, fc, al);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册