/*
* 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;
/**
* 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.
*
* @since 1.5
* @author Doug Lea
* @param The result type returned by this FutureTask's get method
*/
public class FutureTask extends CancellableTask implements Future {
/**
* Callable created in FutureTask(runnable, result) constructor
*/
private static class RunnableAsCallable implements Callable {
private final Runnable runnable;
private final V result;
RunnableAsCallable(Runnable runnable, V result) {
this.runnable = runnable;
this.result = result;
}
public V call() {
runnable.run();
return result;
}
}
/**
* 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) {
// must set after super ctor call to use inner class
super();
if (callable == null)
throw new NullPointerException();
setRunnable(new InnerCancellableFuture(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
* Boolean.TRUE.
* @throws NullPointerException if runnable is null
*/
public FutureTask(final Runnable runnable, final V result) {
super();
if (runnable == null)
throw new NullPointerException();
setRunnable(new InnerCancellableFuture
(new RunnableAsCallable(runnable, result)));
}
/**
* Waits if necessary for the computation to complete, and then retrieves
* its result.
*
* @return the computed result
* @throws CancellationException if task producing this value was
* cancelled before completion
* @throws ExecutionException if the underlying computation threw
* an exception
* @throws InterruptedException if current thread was interrupted
* while waiting
*/
public V get() throws InterruptedException, ExecutionException {
return ((InnerCancellableFuture)getRunnable()).get();
}
/**
* Waits if necessary for at most the given time for the computation to
* complete, and then retrieves its result.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return value of this task
* @throws CancellationException if task producing this value was
* cancelled before completion
* @throws ExecutionException if the 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 {
return ((InnerCancellableFuture)getRunnable()).get(timeout, unit);
}
/**
* Sets the value of this task to the given value. After this
* method is called, the computation is assumed to be completed --
* threads already waiting for the result via get are
* unblocked, and future attempts to retrieve the result will not
* block. While not explicitly disallowed, it is rarely a good idea
* to invoke set more than once.
*
* @param v the value
*
*/
protected void set(V v) {
((InnerCancellableFuture)getRunnable()).set(v);
}
/**
* Indicates that the computation has failed. After this method
* is called, the computation is assumed to be completed, and any
* attempt to retrieve the result will throw an ExecutionException
* wrapping the exception provided here.
*
* @param t the throwable
*/
protected void setException(Throwable t) {
((InnerCancellableFuture)getRunnable()).setException(t);
}
}