diff options
Diffstat (limited to 'guava/src/com/google/common/util/concurrent/Futures.java')
-rw-r--r-- | guava/src/com/google/common/util/concurrent/Futures.java | 280 |
1 files changed, 157 insertions, 123 deletions
diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java index dc2f10450..6bad226b5 100644 --- a/guava/src/com/google/common/util/concurrent/Futures.java +++ b/guava/src/com/google/common/util/concurrent/Futures.java @@ -16,6 +16,7 @@ package com.google.common.util.concurrent; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.util.concurrent.Internal.toNanosSaturated; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; @@ -28,11 +29,11 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.CollectionFuture.ListFuture; import com.google.common.util.concurrent.ImmediateFuture.ImmediateCancelledFuture; -import com.google.common.util.concurrent.ImmediateFuture.ImmediateFailedCheckedFuture; import com.google.common.util.concurrent.ImmediateFuture.ImmediateFailedFuture; -import com.google.common.util.concurrent.ImmediateFuture.ImmediateSuccessfulCheckedFuture; -import com.google.common.util.concurrent.ImmediateFuture.ImmediateSuccessfulFuture; +import com.google.common.util.concurrent.internal.InternalFutureFailureAccess; +import com.google.common.util.concurrent.internal.InternalFutures; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; @@ -40,6 +41,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -60,7 +62,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; * monitoring, debugging, and cancellation. Examples of frameworks include: * * <ul> - * <li><a href="http://google.github.io/dagger/producers.html">Dagger Producers</a> + * <li><a href="https://dagger.dev/producers.html">Dagger Producers</a> * </ul> * * <p>If you do chain your operations manually, you may want to use {@link FluentFuture}. @@ -121,77 +123,29 @@ public final class Futures extends GwtFuturesCatchingSpecialization { private Futures() {} /** - * Creates a {@link CheckedFuture} out of a normal {@link ListenableFuture} and a {@link Function} - * that maps from {@link Exception} instances into the appropriate checked type. - * - * <p><b>Warning:</b> We recommend against using {@code CheckedFuture} in new projects. {@code - * CheckedFuture} is difficult to build libraries atop. {@code CheckedFuture} ports of methods - * like {@link Futures#transformAsync} have historically had bugs, and some of these bugs are - * necessary, unavoidable consequences of the {@code CheckedFuture} API. Additionally, {@code - * CheckedFuture} encourages users to take exceptions from one thread and rethrow them in another, - * producing confusing stack traces. - * - * <p>The given mapping function will be applied to an {@link InterruptedException}, a {@link - * CancellationException}, or an {@link ExecutionException}. See {@link Future#get()} for details - * on the exceptions thrown. - * - * @since 9.0 (source-compatible since 1.0) - * @deprecated {@link CheckedFuture} cannot properly support the chained operations that are the - * primary goal of {@link ListenableFuture}. {@code CheckedFuture} also encourages users to - * rethrow exceptions from one thread in another thread, producing misleading stack traces. - * Additionally, it has a surprising policy about which exceptions to map and which to leave - * untouched. Guava users who want a {@code CheckedFuture} can fork the classes for their own - * use, possibly specializing them to the particular exception type they use. We recommend - * that most people use {@code ListenableFuture} and perform any exception wrapping - * themselves. This method is scheduled for removal from Guava in January 2019. - */ - // TODO(b/72241575): Remove by 2019-01 - @Beta - @Deprecated - @GwtIncompatible // TODO - public static <V, X extends Exception> CheckedFuture<V, X> makeChecked( - ListenableFuture<V> future, Function<? super Exception, X> mapper) { - return new MappingCheckedFuture<>(checkNotNull(future), mapper); - } - - /** * Creates a {@code ListenableFuture} which has its value set immediately upon construction. The * getters just return the value. This {@code Future} can't be canceled or timed out and its * {@code isDone()} method always returns {@code true}. */ public static <V> ListenableFuture<V> immediateFuture(@Nullable V value) { if (value == null) { - // This cast is safe because null is assignable to V for all V (i.e. it is covariant) - @SuppressWarnings({"unchecked", "rawtypes"}) - ListenableFuture<V> typedNull = (ListenableFuture) ImmediateSuccessfulFuture.NULL; + // This cast is safe because null is assignable to V for all V (i.e. it is bivariant) + @SuppressWarnings("unchecked") + ListenableFuture<V> typedNull = (ListenableFuture<V>) ImmediateFuture.NULL; return typedNull; } - return new ImmediateSuccessfulFuture<V>(value); + return new ImmediateFuture<>(value); } /** - * Returns a {@code CheckedFuture} which has its value set immediately upon construction. + * Returns a successful {@code ListenableFuture<Void>}. This method is equivalent to {@code + * immediateFuture(null)} except that it is restricted to produce futures of type {@code Void}. * - * <p>The returned {@code Future} can't be cancelled, and its {@code isDone()} method always - * returns {@code true}. Calling {@code get()} or {@code checkedGet()} will immediately return the - * provided value. - * - * @deprecated {@link CheckedFuture} cannot properly support the chained operations that are the - * primary goal of {@link ListenableFuture}. {@code CheckedFuture} also encourages users to - * rethrow exceptions from one thread in another thread, producing misleading stack traces. - * Additionally, it has a surprising policy about which exceptions to map and which to leave - * untouched. Guava users who want a {@code CheckedFuture} can fork the classes for their own - * use, possibly specializing them to the particular exception type they use. We recommend - * that most people use {@code ListenableFuture} and perform any exception wrapping - * themselves. This method is scheduled for removal from Guava in January 2019. + * @since 29.0 */ - // TODO(b/72241893): Remove by 2019-01 - @Beta - @Deprecated - @GwtIncompatible // TODO - public static <V, X extends Exception> CheckedFuture<V, X> immediateCheckedFuture( - @Nullable V value) { - return new ImmediateSuccessfulCheckedFuture<>(value); + @SuppressWarnings("unchecked") + public static ListenableFuture<Void> immediateVoidFuture() { + return (ListenableFuture<Void>) ImmediateFuture.NULL; } /** @@ -217,30 +171,30 @@ public final class Futures extends GwtFuturesCatchingSpecialization { } /** - * Returns a {@code CheckedFuture} which has an exception set immediately upon construction. + * Executes {@code callable} on the specified {@code executor}, returning a {@code Future}. * - * <p>The returned {@code Future} can't be cancelled, and its {@code isDone()} method always - * returns {@code true}. Calling {@code get()} will immediately throw the provided {@code - * Exception} wrapped in an {@code ExecutionException}, and calling {@code checkedGet()} will - * throw the provided exception itself. - * - * @deprecated {@link CheckedFuture} cannot properly support the chained operations that are the - * primary goal of {@link ListenableFuture}. {@code CheckedFuture} also encourages users to - * rethrow exceptions from one thread in another thread, producing misleading stack traces. - * Additionally, it has a surprising policy about which exceptions to map and which to leave - * untouched. Guava users who want a {@code CheckedFuture} can fork the classes for their own - * use, possibly specializing them to the particular exception type they use. We recommend - * that most people use {@code ListenableFuture} and perform any exception wrapping - * themselves. This method is scheduled for removal from Guava in January 2019. + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.2 */ - // TODO(b/72241500): Remove by 2019-01 @Beta - @Deprecated - @GwtIncompatible // TODO - public static <V, X extends Exception> CheckedFuture<V, X> immediateFailedCheckedFuture( - X exception) { - checkNotNull(exception); - return new ImmediateFailedCheckedFuture<>(exception); + public static <O> ListenableFuture<O> submit(Callable<O> callable, Executor executor) { + TrustedListenableFutureTask<O> task = TrustedListenableFutureTask.create(callable); + executor.execute(task); + return task; + } + + /** + * Executes {@code runnable} on the specified {@code executor}, returning a {@code Future} that + * will complete after execution. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.2 + */ + @Beta + public static ListenableFuture<Void> submit(Runnable runnable, Executor executor) { + TrustedListenableFutureTask<Void> task = TrustedListenableFutureTask.create(runnable, null); + executor.execute(task); + return task; } /** @@ -260,6 +214,19 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. * * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + public static <O> ListenableFuture<O> scheduleAsync( + AsyncCallable<O> callable, Duration delay, ScheduledExecutorService executorService) { + return scheduleAsync(callable, toNanosSaturated(delay), TimeUnit.NANOSECONDS, executorService); + } + + /** + * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution * @since 23.0 */ @Beta @@ -304,9 +271,7 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * }</pre> * * <p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the discussion in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. All its warnings about heavyweight listeners are also applicable to heavyweight - * functions passed to this method. + * the warnings the {@link MoreExecutors#directExecutor} documentation. * * @param input the primary input {@code Future} * @param exceptionType the exception type that triggers use of {@code fallback}. The exception @@ -371,11 +336,7 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * }</pre> * * <p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the discussion in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. All its warnings about heavyweight listeners are also applicable to heavyweight - * functions passed to this method. (Specifically, {@code directExecutor} functions should avoid - * heavyweight operations inside {@code AsyncFunction.apply}. Any heavyweight operations should - * occur in other threads responsible for completing the returned {@code Future}.) + * the warnings the {@link MoreExecutors#directExecutor} documentation. * * @param input the primary input {@code Future} * @param exceptionType the exception type that triggers use of {@code fallback}. The exception @@ -409,6 +370,24 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * * @param delegate The future to delegate to. * @param time when to timeout the future + * @param scheduledExecutor The executor service to enforce the timeout. + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + public static <V> ListenableFuture<V> withTimeout( + ListenableFuture<V> delegate, Duration time, ScheduledExecutorService scheduledExecutor) { + return withTimeout(delegate, toNanosSaturated(time), TimeUnit.NANOSECONDS, scheduledExecutor); + } + + /** + * Returns a future that delegates to another but will finish early (via a {@link + * TimeoutException} wrapped in an {@link ExecutionException}) if the specified duration expires. + * + * <p>The delegate future is interrupted and cancelled if it times out. + * + * @param delegate The future to delegate to. + * @param time when to timeout the future * @param unit the time unit of the time parameter * @param scheduledExecutor The executor service to enforce the timeout. * @since 19.0 @@ -443,11 +422,7 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * }</pre> * * <p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the discussion in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. All its warnings about heavyweight listeners are also applicable to heavyweight - * functions passed to this method. (Specifically, {@code directExecutor} functions should avoid - * heavyweight operations inside {@code AsyncFunction.apply}. Any heavyweight operations should - * occur in other threads responsible for completing the returned {@code Future}.) + * the warnings the {@link MoreExecutors#directExecutor} documentation. * * <p>The returned {@code Future} attempts to keep its cancellation state in sync with that of the * input future and that of the future returned by the chain function. That is, if the returned @@ -483,9 +458,7 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * }</pre> * * <p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the discussion in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. All its warnings about heavyweight listeners are also applicable to heavyweight - * functions passed to this method. + * the warnings the {@link MoreExecutors#directExecutor} documentation. * * <p>The returned {@code Future} attempts to keep its cancellation state in sync with that of the * input future. That is, if the returned {@code Future} is cancelled, it will attempt to cancel @@ -578,6 +551,9 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * * <p>The list of results is in the same order as the input list. * + * <p>This differs from {@link #successfulAsList(ListenableFuture[])} in that it will return a + * failed future if any of the items fails. + * * <p>Canceling this future will attempt to cancel all the component futures, and if any of the * provided futures fails or is canceled, this one is, too. * @@ -597,6 +573,9 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * * <p>The list of results is in the same order as the input list. * + * <p>This differs from {@link #successfulAsList(Iterable)} in that it will return a failed future + * if any of the items fails. + * * <p>Canceling this future will attempt to cancel all the component futures, and if any of the * provided futures fails or is canceled, this one is, too. * @@ -614,6 +593,8 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're * successful. * + * <p>Any failures from the input futures will not be propagated to the returned future. + * * @since 20.0 */ @Beta @@ -626,6 +607,8 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're * successful. * + * <p>Any failures from the input futures will not be propagated to the returned future. + * * @since 20.0 */ @Beta @@ -818,6 +801,11 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * {@code null} (which is indistinguishable from the future having a successful value of {@code * null}). * + * <p>The list of results is in the same order as the input list. + * + * <p>This differs from {@link #allAsList(ListenableFuture[])} in that it's tolerant of failed + * futures for any of the items, representing them as {@code null} in the result list. + * * <p>Canceling this future will attempt to cancel all the component futures. * * @param futures futures to combine @@ -838,6 +826,11 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * {@code null} (which is indistinguishable from the future having a successful value of {@code * null}). * + * <p>The list of results is in the same order as the input list. + * + * <p>This differs from {@link #allAsList(Iterable)} in that it's tolerant of failed futures for + * any of the items, representing them as {@code null} in the result list. + * * <p>Canceling this future will attempt to cancel all the component futures. * * @param futures futures to combine @@ -1014,6 +1007,11 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * callbacks, but any callback added through this method is guaranteed to be called once the * computation is complete. * + * <p>Exceptions thrown by a {@code callback} will be propagated up to the executor. Any exception + * thrown during {@code Executor.execute} (e.g., a {@code RejectedExecutionException} or an + * exception thrown by {@linkplain MoreExecutors#directExecutor direct execution}) will be caught + * and logged. + * * <p>Example: * * <pre>{@code @@ -1031,9 +1029,7 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * }</pre> * * <p>When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the discussion in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. All its warnings about heavyweight listeners are also applicable to heavyweight - * callbacks passed to this method. + * the warnings the {@link MoreExecutors#directExecutor} documentation. * * <p>For a more general interface to attach a completion listener to a {@code Future}, see {@link * ListenableFuture#addListener addListener}. @@ -1063,6 +1059,14 @@ public final class Futures extends GwtFuturesCatchingSpecialization { @Override public void run() { + if (future instanceof InternalFutureFailureAccess) { + Throwable failure = + InternalFutures.tryInternalFastPathGetFailure((InternalFutureFailureAccess) future); + if (failure != null) { + callback.onFailure(failure); + return; + } + } final V value; try { value = getDone(future); @@ -1210,6 +1214,57 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * @throws CancellationException if {@code get} throws a {@code CancellationException} * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or * does not have a suitable constructor + * @since 28.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // reflection + public static <V, X extends Exception> V getChecked( + Future<V> future, Class<X> exceptionClass, Duration timeout) throws X { + return getChecked(future, exceptionClass, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * Returns the result of {@link Future#get(long, TimeUnit)}, converting most exceptions to a new + * instance of the given checked exception type. This reduces boilerplate for a common use of + * {@code Future} in which it is unnecessary to programmatically distinguish between exception + * types or to extract other information from the exception instance. + * + * <p>Exceptions from {@code Future.get} are treated as follows: + * + * <ul> + * <li>Any {@link ExecutionException} has its <i>cause</i> wrapped in an {@code X} if the cause + * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code + * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. + * <li>Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the + * interrupt). + * <li>Any {@link TimeoutException} is wrapped in an {@code X}. + * <li>Any {@link CancellationException} is propagated untouched, as is any other {@link + * RuntimeException} (though {@code get} implementations are discouraged from throwing such + * exceptions). + * </ul> + * + * <p>The overall principle is to continue to treat every checked exception as a checked + * exception, every unchecked exception as an unchecked exception, and every error as an error. In + * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the + * new stack trace matches that of the current thread. + * + * <p>Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor + * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} + * (preferring constructors with at least one {@code String}) and calling the constructor via + * reflection. If the exception did not already have a cause, one is set by calling {@link + * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code + * IllegalArgumentException} is thrown. + * + * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} + * whose cause is not itself a checked exception + * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a + * {@code RuntimeException} as its cause + * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code + * Error} as its cause + * @throws CancellationException if {@code get} throws a {@code CancellationException} + * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or + * does not have a suitable constructor * @since 19.0 (in 10.0 as {@code get} and with different parameter order) */ @Beta @@ -1289,25 +1344,4 @@ public final class Futures extends GwtFuturesCatchingSpecialization { * If you think you would use this method, let us know. You might also also look into the * Fork-Join framework: http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html */ - - /** - * A checked future that uses a function to map from exceptions to the appropriate checked type. - */ - @GwtIncompatible // TODO - private static class MappingCheckedFuture<V, X extends Exception> - extends AbstractCheckedFuture<V, X> { - - final Function<? super Exception, X> mapper; - - MappingCheckedFuture(ListenableFuture<V> delegate, Function<? super Exception, X> mapper) { - super(delegate); - - this.mapper = checkNotNull(mapper); - } - - @Override - protected X mapException(Exception e) { - return mapper.apply(e); - } - } } |