jaroslav@1890: /* jaroslav@1890: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@1890: * jaroslav@1890: * This code is free software; you can redistribute it and/or modify it jaroslav@1890: * under the terms of the GNU General Public License version 2 only, as jaroslav@1890: * published by the Free Software Foundation. Oracle designates this jaroslav@1890: * particular file as subject to the "Classpath" exception as provided jaroslav@1890: * by Oracle in the LICENSE file that accompanied this code. jaroslav@1890: * jaroslav@1890: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@1890: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@1890: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@1890: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@1890: * accompanied this code). jaroslav@1890: * jaroslav@1890: * You should have received a copy of the GNU General Public License version jaroslav@1890: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@1890: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@1890: * jaroslav@1890: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@1890: * or visit www.oracle.com if you need additional information or have any jaroslav@1890: * questions. jaroslav@1890: */ jaroslav@1890: jaroslav@1890: /* jaroslav@1890: * This file is available under and governed by the GNU General Public jaroslav@1890: * License version 2 only, as published by the Free Software Foundation. jaroslav@1890: * However, the following notice accompanied the original version of this jaroslav@1890: * file: jaroslav@1890: * jaroslav@1890: * Written by Doug Lea with assistance from members of JCP JSR-166 jaroslav@1890: * Expert Group and released to the public domain, as explained at jaroslav@1890: * http://creativecommons.org/publicdomain/zero/1.0/ jaroslav@1890: */ jaroslav@1890: jaroslav@1890: package java.util.concurrent; jaroslav@1890: import java.util.concurrent.locks.*; jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * A cancellable asynchronous computation. This class provides a base jaroslav@1890: * implementation of {@link Future}, with methods to start and cancel jaroslav@1890: * a computation, query to see if the computation is complete, and jaroslav@1890: * retrieve the result of the computation. The result can only be jaroslav@1890: * retrieved when the computation has completed; the get jaroslav@1890: * method will block if the computation has not yet completed. Once jaroslav@1890: * the computation has completed, the computation cannot be restarted jaroslav@1890: * or cancelled. jaroslav@1890: * jaroslav@1890: *

A FutureTask can be used to wrap a {@link Callable} or jaroslav@1890: * {@link java.lang.Runnable} object. Because FutureTask jaroslav@1890: * implements Runnable, a FutureTask can be jaroslav@1890: * submitted to an {@link Executor} for execution. jaroslav@1890: * jaroslav@1890: *

In addition to serving as a standalone class, this class provides jaroslav@1890: * protected functionality that may be useful when creating jaroslav@1890: * customized task classes. jaroslav@1890: * jaroslav@1890: * @since 1.5 jaroslav@1890: * @author Doug Lea jaroslav@1890: * @param The result type returned by this FutureTask's get method jaroslav@1890: */ jaroslav@1890: public class FutureTask implements RunnableFuture { jaroslav@1890: /** Synchronization control for FutureTask */ jaroslav@1890: private final Sync sync; jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Creates a FutureTask that will, upon running, execute the jaroslav@1890: * given Callable. jaroslav@1890: * jaroslav@1890: * @param callable the callable task jaroslav@1890: * @throws NullPointerException if callable is null jaroslav@1890: */ jaroslav@1890: public FutureTask(Callable callable) { jaroslav@1890: if (callable == null) jaroslav@1890: throw new NullPointerException(); jaroslav@1890: sync = new Sync(callable); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Creates a FutureTask that will, upon running, execute the jaroslav@1890: * given Runnable, and arrange that get will return the jaroslav@1890: * given result on successful completion. jaroslav@1890: * jaroslav@1890: * @param runnable the runnable task jaroslav@1890: * @param result the result to return on successful completion. If jaroslav@1890: * you don't need a particular result, consider using jaroslav@1890: * constructions of the form: jaroslav@1890: * {@code Future f = new FutureTask(runnable, null)} jaroslav@1890: * @throws NullPointerException if runnable is null jaroslav@1890: */ jaroslav@1890: public FutureTask(Runnable runnable, V result) { jaroslav@1890: sync = new Sync(Executors.callable(runnable, result)); jaroslav@1890: } jaroslav@1890: jaroslav@1890: public boolean isCancelled() { jaroslav@1890: return sync.innerIsCancelled(); jaroslav@1890: } jaroslav@1890: jaroslav@1890: public boolean isDone() { jaroslav@1890: return sync.innerIsDone(); jaroslav@1890: } jaroslav@1890: jaroslav@1890: public boolean cancel(boolean mayInterruptIfRunning) { jaroslav@1890: return sync.innerCancel(mayInterruptIfRunning); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * @throws CancellationException {@inheritDoc} jaroslav@1890: */ jaroslav@1890: public V get() throws InterruptedException, ExecutionException { jaroslav@1890: return sync.innerGet(); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * @throws CancellationException {@inheritDoc} jaroslav@1890: */ jaroslav@1890: public V get(long timeout, TimeUnit unit) jaroslav@1890: throws InterruptedException, ExecutionException, TimeoutException { jaroslav@1890: return sync.innerGet(unit.toNanos(timeout)); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Protected method invoked when this task transitions to state jaroslav@1890: * isDone (whether normally or via cancellation). The jaroslav@1890: * default implementation does nothing. Subclasses may override jaroslav@1890: * this method to invoke completion callbacks or perform jaroslav@1890: * bookkeeping. Note that you can query status inside the jaroslav@1890: * implementation of this method to determine whether this task jaroslav@1890: * has been cancelled. jaroslav@1890: */ jaroslav@1890: protected void done() { } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Sets the result of this Future to the given value unless jaroslav@1890: * this future has already been set or has been cancelled. jaroslav@1890: * This method is invoked internally by the run method jaroslav@1890: * upon successful completion of the computation. jaroslav@1890: * @param v the value jaroslav@1890: */ jaroslav@1890: protected void set(V v) { jaroslav@1890: sync.innerSet(v); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Causes this future to report an ExecutionException jaroslav@1890: * with the given throwable as its cause, unless this Future has jaroslav@1890: * already been set or has been cancelled. jaroslav@1890: * This method is invoked internally by the run method jaroslav@1890: * upon failure of the computation. jaroslav@1890: * @param t the cause of failure jaroslav@1890: */ jaroslav@1890: protected void setException(Throwable t) { jaroslav@1890: sync.innerSetException(t); jaroslav@1890: } jaroslav@1890: jaroslav@1890: // The following (duplicated) doc comment can be removed once jaroslav@1890: // jaroslav@1890: // 6270645: Javadoc comments should be inherited from most derived jaroslav@1890: // superinterface or superclass jaroslav@1890: // is fixed. jaroslav@1890: /** jaroslav@1890: * Sets this Future to the result of its computation jaroslav@1890: * unless it has been cancelled. jaroslav@1890: */ jaroslav@1890: public void run() { jaroslav@1890: sync.innerRun(); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Executes the computation without setting its result, and then jaroslav@1890: * resets this Future to initial state, failing to do so if the jaroslav@1890: * computation encounters an exception or is cancelled. This is jaroslav@1890: * designed for use with tasks that intrinsically execute more jaroslav@1890: * than once. jaroslav@1890: * @return true if successfully run and reset jaroslav@1890: */ jaroslav@1890: protected boolean runAndReset() { jaroslav@1890: return sync.innerRunAndReset(); jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Synchronization control for FutureTask. Note that this must be jaroslav@1890: * a non-static inner class in order to invoke the protected jaroslav@1890: * done method. For clarity, all inner class support jaroslav@1890: * methods are same as outer, prefixed with "inner". jaroslav@1890: * jaroslav@1890: * Uses AQS sync state to represent run status jaroslav@1890: */ jaroslav@1890: private final class Sync extends AbstractQueuedSynchronizer { jaroslav@1890: private static final long serialVersionUID = -7828117401763700385L; jaroslav@1890: jaroslav@1890: /** State value representing that task is ready to run */ jaroslav@1890: private static final int READY = 0; jaroslav@1890: /** State value representing that task is running */ jaroslav@1890: private static final int RUNNING = 1; jaroslav@1890: /** State value representing that task ran */ jaroslav@1890: private static final int RAN = 2; jaroslav@1890: /** State value representing that task was cancelled */ jaroslav@1890: private static final int CANCELLED = 4; jaroslav@1890: jaroslav@1890: /** The underlying callable */ jaroslav@1890: private final Callable callable; jaroslav@1890: /** The result to return from get() */ jaroslav@1890: private V result; jaroslav@1890: /** The exception to throw from get() */ jaroslav@1890: private Throwable exception; jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * The thread running task. When nulled after set/cancel, this jaroslav@1890: * indicates that the results are accessible. Must be jaroslav@1890: * volatile, to ensure visibility upon completion. jaroslav@1890: */ jaroslav@1890: private volatile Thread runner; jaroslav@1890: jaroslav@1890: Sync(Callable callable) { jaroslav@1890: this.callable = callable; jaroslav@1890: } jaroslav@1890: jaroslav@1890: private boolean ranOrCancelled(int state) { jaroslav@1890: return (state & (RAN | CANCELLED)) != 0; jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Implements AQS base acquire to succeed if ran or cancelled jaroslav@1890: */ jaroslav@1890: protected int tryAcquireShared(int ignore) { jaroslav@1890: return innerIsDone() ? 1 : -1; jaroslav@1890: } jaroslav@1890: jaroslav@1890: /** jaroslav@1890: * Implements AQS base release to always signal after setting jaroslav@1890: * final done status by nulling runner thread. jaroslav@1890: */ jaroslav@1890: protected boolean tryReleaseShared(int ignore) { jaroslav@1890: runner = null; jaroslav@1890: return true; jaroslav@1890: } jaroslav@1890: jaroslav@1890: boolean innerIsCancelled() { jaroslav@1890: return getState() == CANCELLED; jaroslav@1890: } jaroslav@1890: jaroslav@1890: boolean innerIsDone() { jaroslav@1890: return ranOrCancelled(getState()) && runner == null; jaroslav@1890: } jaroslav@1890: jaroslav@1890: V innerGet() throws InterruptedException, ExecutionException { jaroslav@1890: acquireSharedInterruptibly(0); jaroslav@1890: if (getState() == CANCELLED) jaroslav@1890: throw new CancellationException(); jaroslav@1890: if (exception != null) jaroslav@1890: throw new ExecutionException(exception); jaroslav@1890: return result; jaroslav@1890: } jaroslav@1890: jaroslav@1890: V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException { jaroslav@1890: if (!tryAcquireSharedNanos(0, nanosTimeout)) jaroslav@1890: throw new TimeoutException(); jaroslav@1890: if (getState() == CANCELLED) jaroslav@1890: throw new CancellationException(); jaroslav@1890: if (exception != null) jaroslav@1890: throw new ExecutionException(exception); jaroslav@1890: return result; jaroslav@1890: } jaroslav@1890: jaroslav@1890: void innerSet(V v) { jaroslav@1890: for (;;) { jaroslav@1890: int s = getState(); jaroslav@1890: if (s == RAN) jaroslav@1890: return; jaroslav@1890: if (s == CANCELLED) { jaroslav@1890: // aggressively release to set runner to null, jaroslav@1890: // in case we are racing with a cancel request jaroslav@1890: // that will try to interrupt runner jaroslav@1890: releaseShared(0); jaroslav@1890: return; jaroslav@1890: } jaroslav@1890: if (compareAndSetState(s, RAN)) { jaroslav@1890: result = v; jaroslav@1890: releaseShared(0); jaroslav@1890: done(); jaroslav@1890: return; jaroslav@1890: } jaroslav@1890: } jaroslav@1890: } jaroslav@1890: jaroslav@1890: void innerSetException(Throwable t) { jaroslav@1890: for (;;) { jaroslav@1890: int s = getState(); jaroslav@1890: if (s == RAN) jaroslav@1890: return; jaroslav@1890: if (s == CANCELLED) { jaroslav@1890: // aggressively release to set runner to null, jaroslav@1890: // in case we are racing with a cancel request jaroslav@1890: // that will try to interrupt runner jaroslav@1890: releaseShared(0); jaroslav@1890: return; jaroslav@1890: } jaroslav@1890: if (compareAndSetState(s, RAN)) { jaroslav@1890: exception = t; jaroslav@1890: releaseShared(0); jaroslav@1890: done(); jaroslav@1890: return; jaroslav@1890: } jaroslav@1890: } jaroslav@1890: } jaroslav@1890: jaroslav@1890: boolean innerCancel(boolean mayInterruptIfRunning) { jaroslav@1890: for (;;) { jaroslav@1890: int s = getState(); jaroslav@1890: if (ranOrCancelled(s)) jaroslav@1890: return false; jaroslav@1890: if (compareAndSetState(s, CANCELLED)) jaroslav@1890: break; jaroslav@1890: } jaroslav@1890: if (mayInterruptIfRunning) { jaroslav@1890: Thread r = runner; jaroslav@1890: if (r != null) jaroslav@1890: r.interrupt(); jaroslav@1890: } jaroslav@1890: releaseShared(0); jaroslav@1890: done(); jaroslav@1890: return true; jaroslav@1890: } jaroslav@1890: jaroslav@1890: void innerRun() { jaroslav@1890: if (!compareAndSetState(READY, RUNNING)) jaroslav@1890: return; jaroslav@1890: jaroslav@1890: runner = Thread.currentThread(); jaroslav@1890: if (getState() == RUNNING) { // recheck after setting thread jaroslav@1890: V result; jaroslav@1890: try { jaroslav@1890: result = callable.call(); jaroslav@1890: } catch (Throwable ex) { jaroslav@1890: setException(ex); jaroslav@1890: return; jaroslav@1890: } jaroslav@1890: set(result); jaroslav@1890: } else { jaroslav@1890: releaseShared(0); // cancel jaroslav@1890: } jaroslav@1890: } jaroslav@1890: jaroslav@1890: boolean innerRunAndReset() { jaroslav@1890: if (!compareAndSetState(READY, RUNNING)) jaroslav@1890: return false; jaroslav@1890: try { jaroslav@1890: runner = Thread.currentThread(); jaroslav@1890: if (getState() == RUNNING) jaroslav@1890: callable.call(); // don't set result jaroslav@1890: runner = null; jaroslav@1890: return compareAndSetState(RUNNING, READY); jaroslav@1890: } catch (Throwable ex) { jaroslav@1890: setException(ex); jaroslav@1890: return false; jaroslav@1890: } jaroslav@1890: } jaroslav@1890: } jaroslav@1890: }