• Netty核心组件之ChannlFuture



    ChannelFuture是Channel的异步I/O操作的结果
    在Netty中,所有的I/O操作都是异步的。这就意味着,任何I/O调用都将会立即返回,但是不保证在I/O调用结束时,这个I/O操作的请求已经完成。
    不过,它会返回一个ChannelFuture实例给你,里面提供了这个I/O操作的结果或者状态。
    一个ChannelFuture的状态不是uncompleted(未完成的)就是completed当开始一个I/O操作时,一个新的ChannelFuture对象就会被创建。这个对象初始化的状态是uncompleted(未完成)--它既不是
    succeeded(成功),failed(失败),也不是cancelled(已取消),因为当前I/O操作还没有完成。当I/O操作完成之后,当前ChannelFuture对象就会被
    标记上详细的信息:成功、失败或者取消 的具体原因。 请注意:失败 和 取消 两种状态属于已完成的状态。 +---------------------------+ | Completed successfully | +---------------------------+ +----> isDone() = true | +--------------------------+ | | isSuccess() = true | | Uncompleted | | +===========================+ +--------------------------+ | | Completed with failure | | isDone() = false | | +---------------------------+ | isSuccess() = false |----+----> isDone() = true | | isCancelled() = false | | | cause() = non-null | | cause() = null | | +===========================+ +--------------------------+ | | Completed by cancellation | | +---------------------------+ +----> isDone() = true | | isCancelled() = true | +---------------------------+
    ChannelFuture中提供了多种方法,以便于 检查当前I/O操作是否已完成、等待当前操作完成、检索当前操作的结果。
    同时,它也允许你添加ChannelFutureListener监听器,这样在I/O操作完成时你就可以收到通知。
    注意:首选#addListener()方法,而不是#await()方法
    无论何时,当你想得到I/O操作完成时的通知时并做接下来的操作的时候,推荐的做法是选择#addListener()方法,而不是#await()方法

    #addListener()方法是非阻塞的,它只是简单的将具体的ChannelFutureListener添加到当前的ChannelFuture中,
    并且当与当前ChannelFuture关联的I/O操作完成时,I/O线程将会通知这些监听器。由于ChannelFutureListener完全不阻塞,
    所以它有最好的性能和资源利用率,但是,如果您不习惯事件驱动的编程,那么实现顺序逻辑可能会很棘手

    相比之下,#await()是阻塞操作。一旦调用,调用者线程将阻塞,直到操作完成为止。
    使用#await()实现顺序逻辑比较容易,但是调用者线程会不必要地阻塞,直到完成I/O操作为止,并且线程间通知的开销也相对较高。
    此外,在特定情况下有死锁的可能性,如下所述:
    请勿在ChannelHandler中调用#await()
    ChannelHandler中的事件处理程序方法通常是由一个I/O线程调用的。
    如果#await()由事件处理程序方法(由I/O线程调用)调用,则它正在等待的I/O操作可能永远不会完成,因为#await()可以阻止正在等待的I/O 操作,这是一个死锁。
    永远不要这样做:
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) {
         ChannelFuture future = ctx.channel().close();
         future.awaitUninterruptibly();
         // Perform post-closure operation
         // ...
     }
     
     可以这样做:
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) {
         ChannelFuture} future = ctx.channel().close();
         future.addListener(new ChannelFutureListener() {
             public void operationComplete(ChannelFuture future) {
                 // Perform post-closure operation
                 // ...
             }
         });
     }
     尽管存在上述缺点,但是在某些情况下调用#await()更方便。
    在这种情况下,请确保不要在I/O线程中调用#await()。否则,将产生BlockingOperationException异常以防止死锁
    不要混淆I/O超时和等待超时
    您使用#await(long),#await(long,TimeUnit),#awaitUninterruptible(long)或#awaitUninterruptible(long)指定的超时值,TimeUnit)与I/O 超时完全无关。
    如果I/O操作超时,则将来将被标记为“completed with failure(失败完成)”,如上图所示。例如,连接超时应通过特定于传输的选项进行配置:
    永远不要这样做:
     Bootstrap b = ...;
     ChannelFuture f = b.connect(...);
     f.awaitUninterruptibly(10, TimeUnit.SECONDS);
     if (f.isCancelled()) {
         // 用户尝试取消连接
     } else if (!f.isSuccess()) {
         //  这里可能产生一个NullPointerException 
         // 因为future可能还没有完成
         f.cause().printStackTrace();
     } else {
         // 成功建立连接
     }
     可以这样做:
     Bootstrap b = ...;
     // 配置连接超时选项
     b.option({ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
     ChannelFuture f = b.connect(...);
     f.awaitUninterruptibly();
     
      // 现在我们可以确定任务完成了
     assert f.isDone();
     
     if (f.isCancelled()) {
         //用户尝试取消连接
     } else if (!f.isSuccess()) {
         f.cause().printStackTrace();
     } else {
         // 成功建立连接
     }
     
  • 相关阅读:
    intel instruction 指令速查
    WinDbg双机调试配置
    MSDN上关于WinDbg的手册
    build temu error about SDL
    taintCheck的实现
    Vim使用taglist功能
    Windows编写driver
    cabal替代脚本
    怎样理解Functor与Monad
    haskell基本语法
  • 原文地址:https://www.cnblogs.com/mmh760/p/14077358.html
Copyright © 2020-2023  润新知