aboutsummaryrefslogtreecommitdiff
path: root/guava/src/com/google/common/util/concurrent/Futures.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/util/concurrent/Futures.java')
-rw-r--r--guava/src/com/google/common/util/concurrent/Futures.java280
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);
- }
- }
}