/* * 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 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; }
 *   }
 * }}
* * 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: *
 {@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 result type returned by this Future's {@code get} method */ public interface Future { /** * Attempts to cancel execution of this task. This method has no * effect if the task is already completed or cancelled, or could * not be cancelled for some other reason. Otherwise, if this * task has not started when {@code cancel} is called, this task * should never run. If the task has already started, then the * {@code mayInterruptIfRunning} parameter determines whether the * thread executing this task (when known by the implementation) * is interrupted in an attempt to stop the task. * *

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 when filtering a stream * of Future objects for the successful tasks and using a mapping * operation to obtain a stream of results. * {@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 19 */ 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 19 */ 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 19 */ 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 19 */ 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(); } } }