异步{@link Channel} I/O操作的结果。
Netty中的所有I/O操作都是异步的。这意味着任何I/O调用都将立即返回,并且不能保证在调用结束时已完成所请求的I/O操作。相反,您将返回一个{@link ChannelFuture}实例,该实例将提供关于I/O操作的结果或状态的信息。
一个{@link ChannelFuture}要么是uncompleted,要么是completed。当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.option({@link ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);
* {@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
Future
Future
Future
Future
Future
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;如果需要,最多等待给定的时间来完成计算,然后检索其结果(如果可用)。