/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ package java.util.concurrent; /** * A {@code Future} represents the result of an asynchronous * computation. Methods are provided to check if the computation is * complete, to wait for its completion, and to retrieve the result of * the computation. The result can only be retrieved using method * {@code get} when the computation has completed, blocking if * necessary until it is ready. Cancellation is performed by the * {@code cancel} method. Additional methods are provided to * determine if the task completed normally or was cancelled. Once a * computation has completed, the computation cannot be cancelled. * If you would like to use a {@code Future} for the sake * of cancellability but not provide a usable result, you can * declare types of the form {@code Future>} and * return {@code null} as a result of the underlying task. * *
Sample Usage (Note that the following classes are all * made-up.) * *
{@code * interface ArchiveSearcher { String search(String target); } * class App { * ExecutorService executor = ...; * ArchiveSearcher searcher = ...; * void showSearch(String target) throws InterruptedException { * Callable* * The {@link FutureTask} class is an implementation of {@code Future} that * implements {@code Runnable}, and so may be executed by an {@code Executor}. * For example, the above construction with {@code submit} could be replaced by: *task = () -> searcher.search(target); * Future future = executor.submit(task); * displayOtherThings(); // do other things while searching * try { * displayText(future.get()); // use future * } catch (ExecutionException ex) { cleanup(); return; } * } * }}
{@code * FutureTask* *future = new FutureTask<>(task); * executor.execute(future);}
Memory consistency effects: Actions taken by the asynchronous computation
* happen-before
* actions following the corresponding {@code Future.get()} in another thread.
*
* @see FutureTask
* @see Executor
* @since 1.5
* @author Doug Lea
* @param The return value from this method does not necessarily
* indicate whether the task is now cancelled; use {@link
* #isCancelled}.
*
* @param mayInterruptIfRunning {@code true} if the thread
* executing this task should be interrupted (if the thread is
* known to the implementation); otherwise, in-progress tasks are
* allowed to complete
* @return {@code false} if the task could not be cancelled,
* typically because it has already completed; {@code true}
* otherwise. If two or more threads cause a task to be cancelled,
* then at least one of them returns {@code true}. Implementations
* may provide stronger guarantees.
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* Returns {@code true} if this task was cancelled before it completed
* normally.
*
* @return {@code true} if this task was cancelled before it completed
*/
boolean isCancelled();
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
boolean isDone();
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
/**
* Waits if necessary for at most the given time for the computation
* 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 the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws TimeoutException if the wait timed out
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
/**
* Returns the computed result, without waiting.
*
* This method is for cases where the caller knows that the task has
* already completed successfully, for example a filter-map of a stream of
* Future objects where the filter matches tasks that completed successfully.
* {@snippet lang=java :
* results = futures.stream()
* .filter(f -> f.state() == Future.State.SUCCESS)
* .map(Future::resultNow)
* .toList();
* }
*
* @implSpec
* The default implementation invokes {@code isDone()} to test if the task
* has completed. If done, it invokes {@code get()} to obtain the result.
*
* @return the computed result
* @throws IllegalStateException if the task has not completed or the task
* did not complete with a result
* @since 99
*/
default V resultNow() {
if (!isDone())
throw new IllegalStateException("Task has not completed");
boolean interrupted = false;
try {
while (true) {
try {
return get();
} catch (InterruptedException e) {
interrupted = true;
} catch (ExecutionException e) {
throw new IllegalStateException("Task completed with exception");
} catch (CancellationException e) {
throw new IllegalStateException("Task was cancelled");
}
}
} finally {
if (interrupted) Thread.currentThread().interrupt();
}
}
/**
* Returns the exception thrown by the task, without waiting.
*
* This method is for cases where the caller knows that the task
* has already completed with an exception.
*
* @implSpec
* The default implementation invokes {@code isDone()} to test if the task
* has completed. If done and not cancelled, it invokes {@code get()} and
* catches the {@code ExecutionException} to obtain the exception.
*
* @return the exception thrown by the task
* @throws IllegalStateException if the task has not completed, the task
* completed normally, or the task was cancelled
* @since 99
*/
default Throwable exceptionNow() {
if (!isDone())
throw new IllegalStateException("Task has not completed");
if (isCancelled())
throw new IllegalStateException("Task was cancelled");
boolean interrupted = false;
try {
while (true) {
try {
get();
throw new IllegalStateException("Task completed with a result");
} catch (InterruptedException e) {
interrupted = true;
} catch (ExecutionException e) {
return e.getCause();
}
}
} finally {
if (interrupted) Thread.currentThread().interrupt();
}
}
/**
* Represents the computation state.
* @since 99
*/
enum State {
/**
* The task has not completed.
*/
RUNNING,
/**
* The task completed with a result.
* @see Future#resultNow()
*/
SUCCESS,
/**
* The task completed with an exception.
* @see Future#exceptionNow()
*/
FAILED,
/**
* The task was cancelled.
* @see #cancel(boolean)
*/
CANCELLED
}
/**
* {@return the computation state}
*
* @implSpec
* The default implementation uses {@code isDone()}, {@code isCancelled()},
* and {@code get()} to determine the state.
*
* @since 99
*/
default State state() {
if (!isDone())
return State.RUNNING;
if (isCancelled())
return State.CANCELLED;
boolean interrupted = false;
try {
while (true) {
try {
get(); // may throw InterruptedException when done
return State.SUCCESS;
} catch (InterruptedException e) {
interrupted = true;
} catch (ExecutionException e) {
return State.FAILED;
}
}
} finally {
if (interrupted) Thread.currentThread().interrupt();
}
}
}