throw new RejectedExecutionException(); // shutting down else if ((q = ws[k]) == null) { // create new queue WorkQueue nq = new WorkQueue(this, null, SHARED_QUEUE); Mutex lock = this.lock; // construct outside lock lock.lock(); else if (q.trySharedPush(task)) { signalWork(); return;
w.runState = -1; if (pass > 0) { w.cancelAll(); if (pass > 1) w.interruptOwner();
/** * Pushes a task if lock is free and array is either big * enough or can be resized to be big enough. * * @param task the task. Caller must ensure non-null. * @return true if submitted */ final boolean trySharedPush(ForkJoinTask<?> task) { boolean submitted = false; if (runState == 0 && U.compareAndSwapInt(this, RUNSTATE, 0, 1)) { ForkJoinTask<?>[] a = array; int s = top; try { if ((a != null && a.length > s + 1 - base) || (a = growArray(false)) != null) { // must presize int j = (((a.length - 1) & s) << ASHIFT) + ABASE; U.putObject(a, (long)j, task); // don't need "ordered" top = s + 1; submitted = true; } } finally { runState = 0; // unlock } } return submitted; }
WorkQueue w; for (int j = 0; j < ws.length; ++j) { if ((w = ws[j]) != null && !w.isEmpty()) { replace = true; break; // in compensation range and tasks available
for (int i = 0; i < ws.length; ++i) { if ((w = ws[i]) != null) { int size = w.queueSize(); if ((i & 1) == 0) qs += size; qt += size; st += w.totalSteals; if (w.isApparentlyUnblocked()) ++rc;
long startTime = 0L; for (int k = 0;;) { if ((s = (joiner.isEmpty() ? // try to help tryHelpStealer(joiner, task) : joiner.tryRemoveAndExec(task))) == 0 && (s = task.status) >= 0) { if (k == 0) {
for (boolean active = true;;) { while ((localTask = w.nextLocalTask()) != null) localTask.doExec(); WorkQueue q = findNonEmptyStealQueue(w); (this, CTL, c = ctl, c + AC_UNIT)); if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) w.runSubtask(t);
w.cancelAll(); // cancel remaining tasks if (w.array != null) // suppress signal if never ran
for (int i = 0; i < ws.length; ++i) { if ((w = ws[i]) != null) { while ((t = w.poll()) != null) { c.add(t); ++count;
/** * Returns a (probably) non-empty steal queue, if one is found * during a random, then cyclic scan, else null. This method must * be retried by caller if, by the time it tries to use the queue, * it is empty. */ private WorkQueue findNonEmptyStealQueue(WorkQueue w) { // Similar to loop in scan(), but ignoring submissions int r = w.seed; r ^= r << 13; r ^= r >>> 17; w.seed = r ^= r << 5; int step = (r >>> 16) | 1; for (WorkQueue[] ws;;) { int rs = runState, m; if ((ws = workQueues) == null || (m = ws.length - 1) < 1) return null; for (int j = (m + 1) << 2; ; r += step) { WorkQueue q = ws[((r << 1) | 1) & m]; if (q != null && !q.isEmpty()) return q; else if (--j < 0) { if (runState == rs) return null; break; } } } }
/** * Returns, but does not unschedule or execute, a task queued by * the current thread but not yet executed, if one is immediately * available. There is no guarantee that this task will actually * be polled or executed next. Conversely, this method may return * null even if a task exists but cannot be accessed without * contention with other threads. This method is designed * primarily to support extensions, and is unlikely to be useful * otherwise. * * <p>This method may be invoked only from within {@code * ForkJoinPool} computations (as may be determined using method * {@link #inForkJoinPool}). Attempts to invoke in other contexts * result in exceptions or errors, possibly including {@code * ClassCastException}. * * @return the next task, or {@code null} if none are available */ protected static ForkJoinTask<?> peekNextLocalTask() { return ((ForkJoinWorkerThread) Thread.currentThread()).workQueue.peek(); }
/** * Returns an estimate of the number of worker threads that are * not blocked waiting to join tasks or for other managed * synchronization. This method may overestimate the * number of running threads. * * @return the number of worker threads */ public int getRunningThreadCount() { int rc = 0; WorkQueue[] ws; WorkQueue w; if ((ws = workQueues) != null) { for (int i = 1; i < ws.length; i += 2) { if ((w = ws[i]) != null && w.isApparentlyUnblocked()) ++rc; } } return rc; }
/** * Stripped-down variant of awaitJoin used by timed joins. Tries * to help join only while there is continuous progress. (Caller * will then enter a timed wait.) * * @param joiner the joining worker * @param task the task * @return task status on exit */ final int helpJoinOnce(WorkQueue joiner, ForkJoinTask<?> task) { int s; while ((s = task.status) >= 0 && (joiner.isEmpty() ? tryHelpStealer(joiner, task) : joiner.tryRemoveAndExec(task)) != 0) ; return s; }
/** * Unschedules and returns, without executing, the next task * queued by the current thread but not yet executed. This method * is designed primarily to support extensions, and is unlikely to * be useful otherwise. * * <p>This method may be invoked only from within {@code * ForkJoinPool} computations (as may be determined using method * {@link #inForkJoinPool}). Attempts to invoke in other contexts * result in exceptions or errors, possibly including {@code * ClassCastException}. * * @return the next task, or {@code null} if none are available */ protected static ForkJoinTask<?> pollNextLocalTask() { return ((ForkJoinWorkerThread) Thread.currentThread()) .workQueue.nextLocalTask(); }
/** * Pushes a task. Call only by owner in unshared queues. * * @param task the task. Caller must ensure non-null. * @throw RejectedExecutionException if array cannot be resized */ final void push(ForkJoinTask<?> task) { ForkJoinTask<?>[] a; ForkJoinPool p; int s = top, m, n; if ((a = array) != null) { // ignore if queue removed U.putOrderedObject (a, (((m = a.length - 1) & s) << ASHIFT) + ABASE, task); if ((n = (top = s + 1) - base) <= 2) { if ((p = pool) != null) p.signalWork(); } else if (n >= m) growArray(true); } }
/** * Creates a ForkJoinWorkerThread operating in the given pool. * * @param pool the pool this thread works in * @throws NullPointerException if pool is null */ protected ForkJoinWorkerThread(ForkJoinPool pool) { super(pool.nextWorkerName()); setDaemon(true); Thread.UncaughtExceptionHandler ueh = pool.ueh; if (ueh != null) setUncaughtExceptionHandler(ueh); this.pool = pool; pool.registerWorker(this.workQueue = new ForkJoinPool.WorkQueue (pool, this, pool.localMode)); }
/** * Executes a top-level task and any local tasks remaining * after execution. */ final void runTask(ForkJoinTask<?> t) { if (t != null) { currentSteal = t; t.doExec(); if (top != base) { // process remaining local tasks if (mode == 0) popAndExecAll(); else pollAndExecAll(); } ++nsteals; currentSteal = null; } }
/** * Returns {@code true} if there are any tasks submitted to this * pool that have not yet begun executing. * * @return {@code true} if there are any queued submissions */ public boolean hasQueuedSubmissions() { WorkQueue[] ws; WorkQueue w; if ((ws = workQueues) != null) { for (int i = 0; i < ws.length; i += 2) { if ((w = ws[i]) != null && !w.isEmpty()) return true; } } return false; }
/** * Removes and returns the next unexecuted submission if one is * available. This method may be useful in extensions to this * class that re-assign work in systems with multiple pools. * * @return the next submission, or {@code null} if none */ protected ForkJoinTask<?> pollSubmission() { WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t; if ((ws = workQueues) != null) { for (int i = 0; i < ws.length; i += 2) { if ((w = ws[i]) != null && (t = w.poll()) != null) return t; } } return null; }
/** * Gets and removes a local or stolen task for the given worker. * * @return a task, if available */ final ForkJoinTask<?> nextTaskFor(WorkQueue w) { for (ForkJoinTask<?> t;;) { WorkQueue q; int b; if ((t = w.nextLocalTask()) != null) return t; if ((q = findNonEmptyStealQueue(w)) == null) return null; if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) return t; } }