- 1. 前言
- 2. 原理解析
- 2.1 ChannelFuture 调用 sync() 的作用
- 2.2 Channel 调用的 closeFuture() 是什么
学习Netty的时候,大家肯定都会看到这么几句代码:
//启动服务端监听
ChannelFuture future = serverBootstrap.bind(7000).sync();
//关闭?
future.channel().closeFuture().sync();
- 问题一:serverBootstrap.bind() 返回的对象是 ChannelFuture ,调用他的 sync() 方法有什么效果?
- 问题二:channel.closeFuture().sync() 到底做了什么?
OK,带着这2个问题我们一步步解析
2. 原理解析 2.1 ChannelFuture 调用 sync() 的作用服务单调用 bind 绑定端口的时候,会将 Channel 注册到 NioEventLoop,这时候会创建一个 DefaultChannelPromise 对象并返回
//SingleThreadEventLoop.java
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
DefaultChannelPromise 和 ChannelFuture 之间存在继承关系:
前面的文章讲过,NioEventLoop 是一个单线程的线程池,整个注册都是通过异步线程处理的。因此我们大胆猜测:调用 sync() 是不是为了阻塞,等待注册结束?
看下 sync 的源码:
//DefaultPromise.java
public Promise sync() throws InterruptedException {
await();
rethrowIfFailed();
return this;
}
这里有个 await() ,翻译过来就是等待的意思,因此继续追踪:
- isDone():每个 DefaultPromise 都有个 result 属性,用来标记当前对象的操作状态
- wait():Object基类方法,如果 isDone() 返回 false,就使当前线程进入阻塞状态,知道其他线程调用 notify/notifyAll 唤醒
阻塞的地方找到了,那肯定有地方进行唤醒,答案就在 safeSetSuccess() 方法,该方法在注册成功后会被调用:
//AbstractChannel.java
protected final void safeSetSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
这里有个 promise.trySuccess() ,底层会调用 setValue0 设置 result = SUCCESS,同时执行 notifyAll() 唤醒线程:
附上 checkNotifyWaiters 代码:
private synchronized boolean checkNotifyWaiters() {
if (waiters > 0) {
notifyAll();
}
return listeners != null;
}
总结: sync 会导致当前执行线程进入阻塞状态,直到异步线程调用 ChannelFuture 对象的 notify/notifyAll 进行唤醒,这一时机通常是在 ChannelFuture 表示的业务逻辑执行完毕后进行触发
2.2 Channel 调用的 closeFuture() 是什么closeFuture() 返回的是 CloseFuture 类型对象,该对象是 Channel 的属性之一。
CloseFuture 继承 DefaultChannelPromise,它只有一个 setClosed() 方法,调用其他方法都会抛出异常:
static final class CloseFuture extends DefaultChannelPromise {
CloseFuture(AbstractChannel ch) {
super(ch);
}
@Override
public ChannelPromise setSuccess() {
throw new IllegalStateException();
}
@Override
public ChannelPromise setFailure(Throwable cause) {
throw new IllegalStateException();
}
@Override
public boolean trySuccess() {
throw new IllegalStateException();
}
@Override
public boolean tryFailure(Throwable cause) {
throw new IllegalStateException();
}
boolean setClosed() {
return super.trySuccess();
}
}
跟踪 setClosed 就可以发现,该方法在发生异常的时候调用,此时会将 closeFuture.sync() 导致的阻塞进行唤醒。
总结: closeFuture.sync() 是为了阻塞当前线程,避免程序直接结束掉而已



