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: }