Netty学习:ChannelFuture

异步{@link Channel} I/O操作的结果。

Netty中的所有I/O操作都是异步的。这意味着任何I/O调用都将立即返回,并且不能保证在调用结束时已完成所请求的I/O操作。相反,您将返回一个{@link ChannelFuture}实例,该实例将提供关于I/O操作的结果或状态的信息。

一个{@link ChannelFuture}要么是<em>uncompleted</em>,要么是<em>completed</em>。当I/O操作开始时,将创建一个新的future对象。新的future最初没有完成——它既没有成功,也没有失败,也没有取消,因为I/O操作还没有完成。如果I/O操作以成功、失败或取消的方式完成,则将用更具体的信息(如失败的原因)将future标记为已完成。请注意,即使失败和取消也属于完成状态。

Completed successfully:isDone() = true,isSuccess() = true

Uncompleted:isDone() = false,isSuccess() = false,isCancelled() = false,cause() = null

Completed with failure:isDone() = true,cause() = non-null

Completed by cancellation:isDone() = true,isCancelled() = true

我们提供了各种方法来检查I/O操作是否已经完成,等待完成,并检索I/O操作的结果。它还允许您添加{@link ChannelFutureListener}s,以便在I/O操作完成时得到通知。

更喜欢{@link #addListener(GenericFutureListener)}而不是{@link # wait()}

建议您尽可能选择{@link #addListener(GenericFutureListener)},而不是{@link # wait()},以便在I/O操作完成时得到通知并执行任何后续任务。

{@link #addListener(GenericFutureListener)}是非阻塞的。它只是将指定的{@link ChannelFutureListener}添加到{@link ChannelFuture},当与future关联的I/O操作完成时,I/O线程将通知侦听器。{@link ChannelFutureListener}具有最佳的性能和资源利用率,因为它根本不会阻塞,但是如果不习惯事件驱动编程,则实现顺序逻辑可能比较困难。

相反,{@link # wait()}是一个阻塞操作。调用后,调用方线程阻塞,直到操作完成。使用{@link # wait()}实现顺序逻辑比较容易,但是调用线程会阻塞,直到I/O操作完成,并且线程间通知的成本相对昂贵。此外,在特定的情况下也有死锁的可能,具体情况如下所述。

不要在{@link ChannelHandler}内部调用{@link # wait()}

{@link ChannelHandler}中的事件处理程序方法通常由I/O线程调用。如果事件处理程序方法调用{@link # wait()}(由I/O线程调用),那么它等待的I/O操作可能永远不会完成,因为{@link # wait()}可能会阻塞它等待的I/O操作,这是一个死锁。

糟糕——永远不要这样做

 * public void channelRead({@link ChannelHandlerContext} ctx, Object msg) {
 *     {@link ChannelFuture} future = ctx.channel().close();
 *     future.awaitUninterruptibly();
 *     // Perform post-closure operation
 *     // ...
 * }

正确的方式:

 * public void channelRead({@link ChannelHandlerContext} ctx, Object msg) {
 *     {@link ChannelFuture} future = ctx.channel().close();
 *     future.addListener(new {@link ChannelFutureListener}() {
 *         public void operationComplete({@link ChannelFuture} future) {
 *             // Perform post-closure operation
 *             // ...
 *         }
 *     });
 * }

尽管上面提到了缺点,但在某些情况下,调用{@link # wait()}更方便。在这种情况下,请确保在I/O线程中不调用{@link # wait()}。否则,将引发{@link BlockingOperationException}以防止死锁。

不要混淆I/O超时和等待超时

使用{@link # wait(long)}、{@link # wait(long, TimeUnit)}、{@link #awaitUninterruptibly(long)}或{@link #awaitUninterruptibly(long, TimeUnit)}指定的超时值与I/O超时完全无关。如果I/O操作超时,则future将标记为“以失败完成”,如上图所示。例如,应该通过特定于传输的选项配置连接超时:

糟糕——永远不要这样做

 * {@link Bootstrap} b = ...;
 * {@link ChannelFuture} 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
 * }

正确的做法:

 * {@link Bootstrap} b = ...;
 * // Configure the connect timeout option.
 * <b>b.option({@link ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);</b>
 * {@link ChannelFuture} 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
 * }

Channel channel();返回与此future发生关联的I/O操作的通道。

boolean isSuccess();当且仅当I/O操作成功完成时返回{@code true}。

boolean isCancellable();当且仅当操作可以通过{@link #cancel(boolean)}取消时,返回{@code true}。

Throwable cause();如果I/O操作失败,则返回失败的I/O操作的原因。如果IO操作成功,返回NULL。

Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);将指定的侦听器添加到此future。当这个future是{@linkplain #isDone() done}时,将通知指定的侦听器。如果这个future已经完成,将立即通知指定的侦听器。

Future<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);从这个future删除每个侦听器的第一个事件。当这个future是{@linkplain #isDone() done}时,将不再通知指定的侦听器。如果指定的侦听器与此future没有关联,则此方法将不执行任何操作并静默返回。

 Future<V> sync() throws InterruptedException;等待这个future 直到完成,如果这个future 失败,则重新抛出失败的原因。

 Future<V> syncUninterruptibly();等待这个future 直到完成,如果这个future 失败,则重新抛出失败的原因。

Future<V> await() throws InterruptedException;等待这个future 的完成。

Future<V> awaitUninterruptibly();等待这个future 的完成而不被打断。这个方法捕获{@link InterruptedException}并无声地丢弃它

boolean await(long timeout, TimeUnit unit) throws InterruptedException;等待这个future 在指定的时间限制内完成。当且仅当future 在指定的时间内完成时,@return {@code true}

boolean await(long timeoutMillis) throws InterruptedException;等待这个future 在指定的时间限制内完成。当且仅当future 在指定的时间内完成时,@return {@code true}

 boolean awaitUninterruptibly(long timeout, TimeUnit unit);

V getNow();不阻塞地返回结果。如果future 还没有完成,这将返回{@code null}。

boolean cancel(boolean mayInterruptIfRunning);如果取消成功,它将以{@link cancationexception}标识future失败。

boolean isCancelled();如果此任务在正常完成之前被取消,则返回{@code true}。

boolean isDone();如果该任务完成,返回{@code true}。完成可能是由于正常终止、异常或取消——在所有这些情况下,该方法将返回{@code true}。

 V get() throws InterruptedException, ExecutionException;如果需要,等待计算完成,然后检索其结果。

V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;如果需要,最多等待给定的时间来完成计算,然后检索其结果(如果可用)。

猜你喜欢

转载自blog.csdn.net/AnY11/article/details/84940510