netty5/common/src/main/java/io/netty/util/concurrent/Future.java

341 lines
16 KiB
Java

/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.concurrent;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
/**
* The result of an asynchronous operation.
* <p>
* An asynchronous operation is one that might be completed outside a given thread of execution. The operation can
* either be performing computation, or I/O, or both.
* <p>
* All I/O operations in Netty are asynchronous. It means any I/O calls will return immediately with no guarantee that
* the requested I/O operation has been completed at the end of the call. Instead, you will be returned with a {@link
* Future} instance which gives you the information about the result or status of the I/O operation.
* <p>
* A {@link Future} is either <em>uncompleted</em> or <em>completed</em>. When an I/O operation begins, a new future
* object is created. The new future is uncompleted initially - it is neither succeeded, failed, nor cancelled because
* the I/O operation is not finished yet. If the I/O operation is finished either successfully, with failure, or by
* cancellation, the future is marked as completed with more specific information, such as the cause of the failure.
* Please note that even failure and cancellation belong to the completed state.
* <pre>
* +---------------------------+
* | Completed successfully |
* +---------------------------+
* +----> isDone() = true |
* +--------------------------+ | | isSuccess() = true |
* | Uncompleted | | +===========================+
* +--------------------------+ | | Completed with failure |
* | isDone() = false | | +---------------------------+
* | isSuccess() = false |----+----> isDone() = true |
* | isCancelled() = false | | | cause() = non-null |
* | cause() = throws | | +===========================+
* | getNow() = throws | | | Completed by cancellation |
* +--------------------------+ | +---------------------------+
* +----> isDone() = true |
* | isCancelled() = true |
* +---------------------------+
* </pre>
* <p>
* Various methods are provided to let you check if the I/O operation has been completed, wait for the completion, and
* retrieve the result of the I/O operation. It also allows you to add {@link FutureListener}s so you can get notified
* when the I/O operation is completed.
*
* <h3>Prefer {@link #addListener(FutureListener)} to {@link #await()}</h3>
* <p>
* It is recommended to prefer {@link #addListener(FutureListener)}, or {@link #addListener(Object,
* FutureContextListener)}, to {@link #await()} wherever possible to get notified when an I/O operation is done and to
* do any follow-up tasks.
* <p>
* The {@link #addListener(FutureListener)} method is non-blocking. It simply adds the specified {@link FutureListener}
* to the {@link Future}, and the I/O thread will notify the listeners when the I/O operation associated with the future
* is done. The {@link FutureListener} and {@link FutureContextListener} callbacks yield the best performance and
* resource utilization because it does not block at all, but it could be tricky to implement a sequential logic if you
* are not used to event-driven programming.
* <p>
* By contrast, {@link #await()} is a blocking operation. Once called, the caller thread blocks until the operation is
* done. It is easier to implement a sequential logic with {@link #await()}, but the caller thread blocks unnecessarily
* until the I/O operation is done and there's relatively expensive cost of inter-thread notification. Moreover, there's
* a chance of dead-lock in a particular circumstance, which is described below.
*
* <h3>Do not call {@link #await()} inside a {@link io.netty.channel.ChannelHandler}</h3>
* <p>
* The event handler methods in {@link io.netty.channel.ChannelHandler} are usually called by an I/O thread. If {@link
* #await()} is called by an event handler method, which is called by the I/O thread, the I/O operation it is waiting
* for might never complete because {@link #await()} can block the I/O operation it is waiting for, which is a
* dead-lock.
* <pre>
* // BAD - NEVER DO THIS
* {@code @Override}
* public void channelRead({@link io.netty.channel.ChannelHandlerContext} ctx, Object msg) {
* {@link Future} future = ctx.channel().close();
* future.awaitUninterruptibly();
* // Perform post-closure operation
* // ...
* }
*
* // GOOD
* {@code @Override}
* public void channelRead({@link io.netty.channel.ChannelHandlerContext} ctx, Object msg) {
* {@link Future} future = ctx.channel().close();
* future.addListener(new {@link FutureListener}() {
* public void operationComplete({@link Future} future) {
* // Perform post-closure operation
* // ...
* }
* });
* }
* </pre>
* <p>
* In spite of the disadvantages mentioned above, there are certainly the cases where it is more convenient to call
* {@link #await()}. In such a case, please make sure you do not call {@link #await()} in an I/O thread. Otherwise,
* {@link BlockingOperationException} will be raised to prevent a dead-lock.
*
* <h3>Do not confuse I/O timeout and await timeout</h3>
* <p>
* The timeout value you specify with {@link #await(long)}, {@link #await(long, TimeUnit)}, {@link
* #awaitUninterruptibly(long)}, or {@link #awaitUninterruptibly(long, TimeUnit)} are not related with I/O timeout at
* all. If an I/O operation times out, the future will be marked as 'completed with failure,' as depicted in the
* diagram above. For example, connect timeout should be configured via a transport-specific option:
* <pre>
* // BAD - NEVER DO THIS
* {@link io.netty.bootstrap.Bootstrap} b = ...;
* {@link Future} f = b.connect(...);
* f.awaitUninterruptibly(10, TimeUnit.SECONDS);
* if (f.isCancelled()) {
* // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
* // You might get a NullPointerException here because the future
* // might not be completed yet.
* f.cause().printStackTrace();
* } else {
* // Connection established successfully
* }
*
* // GOOD
* {@link io.netty.bootstrap.Bootstrap} b = ...;
* // Configure the connect timeout option.
* <b>b.option({@link io.netty.channel.ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);</b>
* {@link Future} f = b.connect(...);
* f.awaitUninterruptibly();
*
* // Now we are sure the future is completed.
* assert f.isDone();
*
* if (f.isCancelled()) {
* // Connection attempt cancelled by user
* } else if (!f.isSuccess()) {
* f.cause().printStackTrace();
* } else {
* // Connection established successfully
* }
* </pre>
*/
@SuppressWarnings("ClassNameSameAsAncestorName")
public interface Future<V> extends java.util.concurrent.Future<V>, AsynchronousResult<V> {
/**
* Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain
* #isDone() done}. If this future is already completed, the specified listener is notified immediately.
*
* @param listener The listener to be called when this future completes. The listener will be passed this future as
* an argument.
* @return this future object.
*/
Future<V> addListener(FutureListener<? super V> listener);
/**
* Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain
* #isDone() done}. If this future is already completed, the specified listener is notified immediately.
*
* @param context The context object that will be passed to the listener when this future completes.
* @param listener The listener to be called when this future completes. The listener will be passed the given
* context, and this future.
* @return this future object.
*/
<C> Future<V> addListener(C context, FutureContextListener<? super C, ? super V> listener);
/**
* Waits for this future until it is done, and rethrows the cause of the failure if this future failed.
*
* @throws CancellationException if the computation was cancelled
* @throws CompletionException if the computation threw an exception.
* @throws InterruptedException if the current thread was interrupted while waiting
*/
Future<V> sync() throws InterruptedException;
/**
* Waits for this future until it is done, and rethrows the cause of the failure if this future failed.
*
* @throws CancellationException if the computation was cancelled
* @throws CompletionException if the computation threw an exception.
*/
Future<V> syncUninterruptibly();
/**
* Waits for this future to be completed.
*
* @throws InterruptedException if the current thread was interrupted
*/
Future<V> await() throws InterruptedException;
/**
* Waits for this future to be completed without interruption. This method catches an {@link InterruptedException}
* and discards it silently.
*/
Future<V> awaitUninterruptibly();
/**
* Waits for this future to be completed within the specified time limit.
*
* @return {@code true} if and only if the future was completed within the specified time limit
* @throws InterruptedException if the current thread was interrupted
*/
boolean await(long timeout, TimeUnit unit) throws InterruptedException;
/**
* Waits for this future to be completed within the specified time limit.
*
* @return {@code true} if and only if the future was completed within the specified time limit
* @throws InterruptedException if the current thread was interrupted
*/
boolean await(long timeoutMillis) throws InterruptedException;
/**
* Waits for this future to be completed within the specified time limit without interruption. This method catches
* an {@link InterruptedException} and discards it silently.
*
* @return {@code true} if and only if the future was completed within the specified time limit
*/
boolean awaitUninterruptibly(long timeout, TimeUnit unit);
/**
* Waits for this future to be completed within the specified time limit without interruption. This method catches
* an {@link InterruptedException} and discards it silently.
*
* @return {@code true} if and only if the future was completed within the specified time limit
*/
boolean awaitUninterruptibly(long timeoutMillis);
/**
* {@inheritDoc}
* <p>
* If the cancellation was successful it will fail the future with a {@link CancellationException}.
*/
@Override
boolean cancel(boolean mayInterruptIfRunning);
@Override
default V get() throws InterruptedException, ExecutionException {
await();
Throwable cause = cause();
if (cause == null) {
return getNow();
}
if (cause instanceof CancellationException) {
throw (CancellationException) cause;
}
throw new ExecutionException(cause);
}
@Override
default V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (await(timeout, unit)) {
Throwable cause = cause();
if (cause == null) {
return getNow();
}
if (cause instanceof CancellationException) {
throw (CancellationException) cause;
}
throw new ExecutionException(cause);
}
throw new TimeoutException();
}
/**
* Returns a {@link FutureCompletionStage} that reflects the state of this {@link Future} and so will receive all
* updates as well.
*/
default FutureCompletionStage<V> asStage() {
return new DefaultFutureCompletionStage<>(this);
}
/**
* Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future} mapped
* through the given mapper function.
* <p>
* If this future fails, then the returned future will fail as well, with the same exception. Cancellation of either
* future will cancel the other. If the mapper function throws, the returned future will fail, but this future will
* be unaffected.
*
* @param mapper The function that will convert the result of this future into the result of the returned future.
* @param <R> The result type of the mapper function, and of the returned future.
* @return A new future instance that will complete with the mapped result of this future.
*/
default <R> Future<R> map(Function<V, R> mapper) {
return Futures.map(this, mapper);
}
/**
* Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future}
* flat-mapped through the given mapper function.
* <p>
* The "flat" in "flat-map" means the given mapper function produces a result that itself is a future-of-R, yet this
* method also returns a future-of-R, rather than a future-of-future-of-R. In other words, if the same mapper
* function was used with the {@link #map(Function)} method, you would get back a {@code Future<Future<R>>}. These
* nested futures are "flattened" into a {@code Future<R>} by this method.
* <p>
* Effectively, this method behaves similar to this serial code, except asynchronously and with proper exception and
* cancellation handling:
* <pre>{@code
* V x = future.sync().getNow();
* Future<R> y = mapper.apply(x);
* R result = y.sync().getNow();
* }</pre>
* <p>
* If the given future fails, then the returned future will fail as well, with the same exception. Cancellation of
* either future will cancel the other. If the mapper function throws, the returned future will fail, but this
* future will be unaffected.
*
* @param mapper The function that will convert the result of this future into the result of the returned future.
* @param <R> The result type of the mapper function, and of the returned future.
* @return A new future instance that will complete with the mapped result of this future.
*/
default <R> Future<R> flatMap(Function<V, Future<R>> mapper) {
return Futures.flatMap(this, mapper);
}
/**
* Link the {@link Future} and {@link Promise} such that if the {@link Future} completes the {@link Promise}
* will be notified. Cancellation is propagated both ways such that if the {@link Future} is cancelled
* the {@link Promise} is cancelled and vice-versa.
*
* @param promise the {@link Promise} which will be notified
* @return itself
*/
default Future<V> cascadeTo(final Promise<? super V> promise) {
Futures.cascade(this, promise);
return this;
}
}