Netty的ChannelFuture和ChannelPromise

在netty中可以通过channelFuture和channelPromise来实现异步操作。,可以通过官方给出的channelFuture的注释来看到关于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分为了四个状态,初始状态为uncompleted,isDone()所返回的状态为false,isSuccess()返回的状态为true,isCancelled()返回的状态为false,cause()所返回的异常为null。

接下来可以看到,可以改变为完成成功,完成失败,完成中被取消三个状态。

从上面也可以看到三个状态的改变也会改变channelFuture的三个状态量。首先不管状态如何改变,只要从未完成状态改变,isDone()都会变为true,然后成功isSuccess()会是true,被取消则isCancelled()则会变成true,异常发生则会cause()返回相应的异常类型。

以上就是channelFuture的基本,而channelPromise作为channelFuture的扩展,在实际作用中发挥上面的功能。

可以从channel的注册看到future的使用的例子。

在注册的步骤达到SingleThreadEventLoop时,则会根据要注册的channel生成相应的channelPromise。

public ChannelFuture register(Channel channel) {
    return register(channel, new DefaultChannelPromise(channel, this));
}

这里的构造方法也表明了channelPromise主要需要的两个成员,毫无疑问,一个就是所对应的需要作出异步处理的channel还有就是这个channel所对应的eventloop。

在注册的过程中,往下面可以看出如果之前的evnetloop所对应的线程与当前的线程不一样的话,真正的注册流程则会作为task任务放入eventloop的阻塞队列异步进行。此时,整个注册操作就会异步进行,那么在注册完毕后,如果需要该channel用来connect或者bind的时候,怎么保证channel的注册状态呢,这个时候channelPromise起到了作用。看到absactUnsafe的register0()方法,值得一提的是一般情况下这个方法已经是异步进行当中的了。

private void register0(ChannelPromise promise) {
    try {
        // check if the channel is still open as it could be closed in the mean time when the register
        // call was outside of the eventLoop
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        doRegister();
        neverRegistered = false;
        registered = true;
        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
        // Only fire a channelActive if the channel has never been registered. This prevents firing
        // multiple channel actives if the channel is deregistered and re-registered.
        if (firstRegistration && isActive()) {
            pipeline.fireChannelActive();
        }
    } catch (Throwable t) {
        // Close the channel directly to avoid FD leak.
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

 

doRegister()方法作为具体的注册业务逻辑,在这之后则会看到safeSetSuccess()方法,而在catch块中也可以看到safeSetFailure()方法,顾名思义,这里的状态变迁可以很清楚的联想到channelFuture那张图的变化。

 

只有在注册完成之后才会调用的safeSetSuccess()方法表明了对注册状态的成功的标记,可以看到这个方法,这个方法调用了channelPromise的trySuccess()方法。

而在channelPromise的trySuccess()方法中,会调用setSuccess0()方法来对状态进行标记。

private boolean setSuccess0(V result) {
    if (isDone()) {
        return false;
    }

    synchronized (this) {
        // Allow only once.
        if (isDone()) {
            return false;
        }
        if (result == null) {
            this.result = SUCCESS;
        } else {
            this.result = result;
        }
        if (hasWaiters()) {
            notifyAll();
        }
    }
    return true;
}

 

由于是异步的情况下,需要保证这里的线程安全,如果这时isDone()表明还未完成,则会把状态量result标位success。

 

而异常的状态标记也与成功类似。

在之后,准备给channel去connect或者bind的时候,就会判断channelPromise的isDone()来选择异步放进eventloop的阻塞队列还是直接进行下面的操作。

但是,如果在需要promise完成时,真正的注册还没有完成,怎么设置在异步等待完成时候的代码逻辑?这个时候就需要listener。

private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }

    if (regFuture.isDone()) {
        // At this point we know that the registration was complete and succesful.
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if (cause != null) {
                    // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                    // IllegalStateException once we try to access the EventLoop of the Channel.
                    promise.setFailure(cause);
                } else {
                    // Registration was successful, so set the correct executor to use.
                    // See https://github.com/netty/netty/issues/2586
                    promise.executor = channel.eventLoop();
                }
                doBind0(regFuture, channel, localAddress, promise);
            }
        });
        return promise;
    }
}

 

看到abstractBootstrap的doBInd()方法,在完成注册步骤之后,要采用doBind0()来继续绑定的逻辑,之前,先会调用isDone()来判断是否已经将注册完成,如果没有,则会给channelPromise添加一个监听器,实现operationComplete()方法,里面实现了如果前面步骤已经结束,则会调用doBind0()方法,当然,也可以看到,在之前的步骤中,已经把注册时候的channelPromise设置为已经完成,这个时候就会生成一个新的promise,来保证接下里的异步作用。

 

那么是何时通知监听器的呢?

现在可以看DefaultPromsie中完整的trySuccess()方法。

public boolean trySuccess(V result) {
    if (setSuccess0(result)) {
        notifyListeners();
        return true;
    }
    return false;
}

 

在通过setSuccess0()方法完成状态量的设置之后,就会通过notifyListeners()方法来通知相应的监听器去执行相应的operationComplete()方法。值得一提的是,如果在添加listener的时候会判断isDone(),如果此时已经完成了相应的异步操作,则会直接调用监听器的方法。

 

 

 

你可能感兴趣的:(netty)