1 /* 2 * Copyright 2013 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty5.util.concurrent; 17 18 import java.util.concurrent.TimeUnit; 19 import java.util.function.Function; 20 21 /** 22 * The result of an asynchronous operation. 23 * <p> 24 * An asynchronous operation is one that might be completed outside a given thread of execution. The operation can 25 * either be performing computation, or I/O, or both. 26 * <p> 27 * All I/O operations in Netty are asynchronous. It means any I/O calls will return immediately with no guarantee that 28 * the requested I/O operation has been completed at the end of the call. Instead, you will be returned with a {@link 29 * Future} instance which gives you the information about the result or status of the I/O operation. 30 * <p> 31 * A {@link Future} is either <em>uncompleted</em> or <em>completed</em>. When an I/O operation begins, a new future 32 * object is created. The new future is uncompleted initially - it is neither succeeded, failed, nor cancelled because 33 * the I/O operation is not finished yet. If the I/O operation is finished either successfully, with failure, or by 34 * cancellation, the future is marked as completed with more specific information, such as the cause of the failure. 35 * Please note that even failure and cancellation belong to the completed state. 36 * <pre> 37 * +---------------------------+ 38 * | Completed successfully | 39 * +---------------------------+ 40 * +----> isDone() = true | 41 * +--------------------------+ | | isSuccess() = true | 42 * | Uncompleted | | +===========================+ 43 * +--------------------------+ | | Completed with failure | 44 * | isDone() = false | | +---------------------------+ 45 * | isSuccess() = false |----+----> isDone() = true | 46 * | isCancelled() = false | | | cause() = non-null | 47 * | cause() = throws | | +===========================+ 48 * | getNow() = throws | | | Completed by cancellation | 49 * +--------------------------+ | +---------------------------+ 50 * +----> isDone() = true | 51 * | isCancelled() = true | 52 * +---------------------------+ 53 * </pre> 54 * <p> 55 * Various methods are provided to let you check if the I/O operation has been completed, wait for the completion, and 56 * retrieve the result of the I/O operation. It also allows you to add {@link FutureListener}s so you can get notified 57 * when the I/O operation is completed. 58 * 59 * <h3>Prefer {@link #addListener(FutureListener)} to {@link FutureCompletionStage#await()}</h3> 60 * <p> 61 * It is recommended to prefer {@link #addListener(FutureListener)}, or {@link #addListener(Object, 62 * FutureContextListener)}, to {@link FutureCompletionStage#await()} wherever possible to get notified when an I/O 63 * operation is done and to do any follow-up tasks. 64 * <p> 65 * The {@link #addListener(FutureListener)} method is non-blocking. It simply adds the specified {@link FutureListener} 66 * to the {@link Future}, and the I/O thread will notify the listeners when the I/O operation associated with the future 67 * is done. The {@link FutureListener} and {@link FutureContextListener} callbacks yield the best performance and 68 * resource utilization because it does not block at all, but it could be tricky to implement a sequential logic if you 69 * are not used to event-driven programming. 70 * <p> 71 * By contrast, {@link FutureCompletionStage#await()} is a blocking operation. Once called, the caller thread blocks 72 * until the operation is done. It is easier to implement a sequential logic with {@link FutureCompletionStage#await()}, 73 * but the caller thread blocks unnecessarily until the I/O operation is done and there's relatively expensive cost of 74 * inter-thread notification. Moreover, there's a chance of deadlock in a particular circumstance, which is 75 * described below. 76 * 77 * <h3>Do not call {@link FutureCompletionStage#await()} inside a {@link io.netty5.channel.ChannelHandler}</h3> 78 * <p> 79 * The event handler methods in {@link io.netty5.channel.ChannelHandler} are usually called by an I/O thread. 80 * If {@link FutureCompletionStage#await()} is called by an event handler method, which is called by the I/O thread, 81 * the I/O operation it is waiting for might never complete because {@link FutureCompletionStage#await()} can block 82 * the I/O operation it is waiting for, which is a deadlock. 83 * <pre> 84 * // BAD - NEVER DO THIS 85 * {@code @Override} 86 * public void channelRead({@link io.netty5.channel.ChannelHandlerContext} ctx, Object msg) { 87 * {@link Future} future = ctx.channel().close(); 88 * future.asStage().await(); 89 * // Perform post-closure operation 90 * // ... 91 * } 92 * 93 * // GOOD 94 * {@code @Override} 95 * public void channelRead({@link io.netty5.channel.ChannelHandlerContext} ctx, Object msg) { 96 * {@link Future} future = ctx.channel().close(); 97 * future.addListener(new {@link FutureListener}() { 98 * public void operationComplete({@link Future} future) { 99 * // Perform post-closure operation 100 * // ... 101 * } 102 * }); 103 * } 104 * </pre> 105 * <p> 106 * In spite of the disadvantages mentioned above, there are certainly the cases where it is more convenient to call 107 * {@link FutureCompletionStage#await()}. In such a case, please make sure you do not call 108 * {@link FutureCompletionStage#await()} in an I/O thread. Otherwise, {@link BlockingOperationException} will be 109 * raised to prevent a deadlock. 110 * 111 * <h3>Do not confuse I/O timeout and await timeout</h3> 112 * <p> 113 * The timeout value you specify with {@link FutureCompletionStage#await(long, TimeUnit)} is not related to the 114 * I/O timeout at all. 115 * If an I/O operation times out, the future will be marked as 'completed with failure,' as depicted in the 116 * diagram above. For example, connect timeout should be configured via a transport-specific option: 117 * <pre> 118 * // BAD - NEVER DO THIS 119 * {@link io.netty5.bootstrap.Bootstrap} b = ...; 120 * {@link Future} f = b.connect(...); 121 * f.asStage().await(10, TimeUnit.SECONDS); 122 * if (f.isCancelled()) { 123 * // Connection attempt cancelled by user 124 * } else if (!f.isSuccess()) { 125 * // You might get a NullPointerException here because the future 126 * // might not be completed yet. 127 * f.cause().printStackTrace(); 128 * } else { 129 * // Connection established successfully 130 * } 131 * 132 * // GOOD 133 * {@link io.netty5.bootstrap.Bootstrap} b = ...; 134 * // Configure the connect timeout option. 135 * <b>b.option({@link io.netty5.channel.ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);</b> 136 * {@link Future} f = b.connect(...); 137 * f.asStage().await(); 138 * 139 * // Now we are sure the future is completed. 140 * assert f.isDone(); 141 * 142 * if (f.isCancelled()) { 143 * // Connection attempt cancelled by user 144 * } else if (!f.isSuccess()) { 145 * f.cause().printStackTrace(); 146 * } else { 147 * // Connection established successfully 148 * } 149 * </pre> 150 */ 151 public interface Future<V> extends AsynchronousResult<V> { 152 /** 153 * Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain 154 * #isDone() done}. If this future is already completed, the specified listener is notified immediately. 155 * 156 * @param listener The listener to be called when this future completes. The listener will be passed this future as 157 * an argument. 158 * @return this future object. 159 */ 160 Future<V> addListener(FutureListener<? super V> listener); 161 162 /** 163 * Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain 164 * #isDone() done}. If this future is already completed, the specified listener is notified immediately. 165 * 166 * @param context The context object that will be passed to the listener when this future completes. 167 * @param listener The listener to be called when this future completes. The listener will be passed the given 168 * context, and this future. 169 * @return this future object. 170 */ 171 <C> Future<V> addListener(C context, FutureContextListener<? super C, ? super V> listener); 172 173 /** 174 * Returns a {@link FutureCompletionStage} that reflects the state of this {@link Future} and so will receive all 175 * updates as well. 176 * <p> 177 * The returned {@link FutureCompletionStage} also implements the JDK {@link java.util.concurrent.Future}, 178 * and has blocking methods not found on the Netty {@code Future} interface, for awaiting the completion. 179 */ 180 FutureCompletionStage<V> asStage(); 181 182 /** 183 * Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future} mapped 184 * through the given mapper function. 185 * <p> 186 * If this future fails, then the returned future will fail as well, with the same exception. Cancellation of either 187 * future will cancel the other. If the mapper function throws, the returned future will fail, but this future will 188 * be unaffected. 189 * 190 * @param mapper The function that will convert the result of this future into the result of the returned future. 191 * @param <R> The result type of the mapper function, and of the returned future. 192 * @return A new future instance that will complete with the mapped result of this future. 193 */ 194 default <R> Future<R> map(Function<V, R> mapper) { 195 return Futures.map(this, mapper); 196 } 197 198 /** 199 * Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future} 200 * flat-mapped through the given mapper function. 201 * <p> 202 * The "flat" in "flat-map" means the given mapper function produces a result that itself is a future-of-R, yet this 203 * method also returns a future-of-R, rather than a future-of-future-of-R. In other words, if the same mapper 204 * function was used with the {@link #map(Function)} method, you would get back a {@code Future<Future<R>>}. These 205 * nested futures are "flattened" into a {@code Future<R>} by this method. 206 * <p> 207 * Effectively, this method behaves similar to this serial code, except asynchronously and with proper exception and 208 * cancellation handling: 209 * <pre>{@code 210 * V x = future.sync().getNow(); 211 * Future<R> y = mapper.apply(x); 212 * R result = y.sync().getNow(); 213 * }</pre> 214 * <p> 215 * If the given future fails, then the returned future will fail as well, with the same exception. Cancellation of 216 * either future will cancel the other. If the mapper function throws, the returned future will fail, but this 217 * future will be unaffected. 218 * 219 * @param mapper The function that will convert the result of this future into the result of the returned future. 220 * @param <R> The result type of the mapper function, and of the returned future. 221 * @return A new future instance that will complete with the mapped result of this future. 222 */ 223 default <R> Future<R> flatMap(Function<V, Future<R>> mapper) { 224 return Futures.flatMap(this, mapper); 225 } 226 227 /** 228 * Link the {@link Future} and {@link Promise} such that if the {@link Future} completes the {@link Promise} 229 * will be notified. Cancellation is propagated both ways such that if the {@link Future} is cancelled 230 * the {@link Promise} is cancelled and vice-versa. 231 * 232 * @param promise the {@link Promise} which will be notified 233 * @return itself 234 */ 235 default Future<V> cascadeTo(final Promise<? super V> promise) { 236 Futures.cascade(this, promise); 237 return this; 238 } 239 }