/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain. Use, modify, and * redistribute this code in any way without acknowledgement. */ package java.util.concurrent; import java.util.concurrent.locks.*; /** * A cancellable asynchronous computation. This class provides a base * implementation of {@link Future}, with methods to start and cancel * a computation, query to see if the computation is complete, and * retrieve the result of the computation. The result can only be * retrieved when the computation has completed; the get * method will block if the computation has not yet completed. Once * the computation has completed, the computation cannot be restarted * or cancelled. * *

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

In addition to serving as a standalone class, this class provides * protected functionality that may be useful when creating * customized task classes. * * @since 1.5 * @author Doug Lea * @param The result type returned by this FutureTask's get method */ public class FutureTask implements Future, Runnable { /** * Special value for "runState" indicating task is cancelled */ private static final Object CANCELLED = new Object(); /** * Special value for "runState" indicating task is completed */ private static final Object DONE = new Object(); /** * Holds the run-state, taking on values: * null = not yet started, * [some thread ref] = running, * DONE = completed normally, * CANCELLED = cancelled (may or may not have ever run). */ private volatile Object runState; /** The underlying callable */ private final Callable callable; /** The result to return from get() */ private V result; /** The exception to throw from get() */ private Throwable exception; private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock.ConditionObject accessible = lock.newCondition(); /** * Constructs a FutureTask that will upon running, execute the * given Callable. * * @param callable the callable task * @throws NullPointerException if callable is null */ public FutureTask(Callable callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; } /** * Constructs a FutureTask that will upon running, execute the * given Runnable, and arrange that get will return the * given result on successful completion. * * @param runnable the runnable task * @param result the result to return on successful completion. If * you don't need a particular result, consider using * constructions of the form: * Future<?> f = new FutureTask<Object>(runnable, null) * @throws NullPointerException if runnable is null */ public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); } public boolean isCancelled() { return runState == CANCELLED; } public boolean isDone() { Object r = runState; return r == DONE || r == CANCELLED; } public boolean cancel(boolean mayInterruptIfRunning) { lock.lock(); try { Object r = runState; if (r == DONE || r == CANCELLED) return false; runState = CANCELLED; accessible.signalAll(); if (mayInterruptIfRunning && r != null && r instanceof Thread) ((Thread)r).interrupt(); } finally{ lock.unlock(); } done(); return true; } /** * Waits if necessary for execution to complete, and then * retrieves its result. * * @return computed result * @throws CancellationException if underlying computation was * cancelled * @throws ExecutionException if underlying computation threw an * exception * @throws InterruptedException if current thread was interrupted * while waiting */ public V get() throws InterruptedException, ExecutionException { lock.lock(); try { for (;;) { Object r = runState; if (r == CANCELLED) throw new CancellationException(); if (r == DONE) { if (exception != null) throw new ExecutionException(exception); else return result; } accessible.await(); } } finally { lock.unlock(); } } /** * Waits if necessary for at most the given time for execution to * complete, and then retrieves its result, if available. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return computed result * @throws CancellationException if underlying computation was * cancelled * @throws ExecutionException if underlying computation threw an * exception * @throws InterruptedException if current thread was interrupted * while waiting * @throws TimeoutException if the wait timed out */ public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { long nanos = unit.toNanos(timeout); lock.lock(); try { for (;;) { Object r = runState; if (r == CANCELLED) throw new CancellationException(); if (r == DONE) { if (exception != null) throw new ExecutionException(exception); else return result; } if (nanos <= 0) throw new TimeoutException(); nanos = accessible.awaitNanos(nanos); } } finally { lock.unlock(); } } /** * Protected method invoked when this task transitions to state * isDone (whether normally or via cancellation). The * default implementation does nothing. Subclasses may override * this method to invoke completion callbacks or perform * bookkeeping. Note that you can query status inside the * implementation of this method to determine whether this task * has been cancelled. */ protected void done() { } /** * Sets the result of this Future to the given value unless * this future has been cancelled * @param v the value */ protected void set(V v) { lock.lock(); try { if (runState == CANCELLED) return; result = v; accessible.signalAll(); runState = DONE; } finally { lock.unlock(); } done(); } /** * Causes this future to report an ExecutionException * with the given throwable as its cause, unless this Future has * been cancelled. * @param t the cause of failure. */ protected void setException(Throwable t) { lock.lock(); try { if (runState == CANCELLED) return; exception = t; accessible.signalAll(); runState = DONE; } finally { lock.unlock(); } done(); } /** * Attempts to set the state of this task to Running, succeeding * only if the state is currently NOT Done, Running, or Cancelled. * @return true if successful */ private boolean setRunning() { lock.lock(); try { if (runState != null) return false; runState = Thread.currentThread(); return true; } finally { lock.unlock(); } } /** * Resets the run state of this task to its initial state unless * it has been cancelled. (Note that a cancelled task cannot be * reset.) * @return true if successful */ private boolean reset() { lock.lock(); try { if (runState == CANCELLED) return false; runState = null; return true; } finally { lock.unlock(); } } /** * Sets this Future to the result of computation unless * it has been cancelled. */ public void run() { if (setRunning()) { try { set(callable.call()); } catch(Throwable ex) { setException(ex); } } } /** * Executes the computation and then resets this Future to initial * state; failing to do so if the computation encounters an * exception or is cancelled. This is designed for use with tasks * that intrinsically execute more than once. * @return true if successfully run and reset */ protected boolean runAndReset() { if (setRunning()) { try { // don't bother to set result; it can't be accessed callable.call(); return reset(); } catch(Throwable ex) { setException(ex); } } return false; } }