为什么出现Future
Thread实现Runnable,它无法返回子线程执行结果。Callable结合Future返回执行结果,实现伪异步:call执行结束,子线程会立即返回一个Future给父线程,父线程不用等待子线程执行,可以继续做自己的事,过段时间调用future.get()获取结果,如果子线程执行结束,可以获取到结果,但如果没有结束,父线程要阻塞等待。一般轮询isDone()来判断,然后再调用get方法。
如何实现netty的被观察者
父线程阻塞,等待子线程完成来唤醒?那不又回到阻塞了么。唤醒机制适用于线程间的同步,特别是在需要等待某个条件或资源时使用。这里我们要实现异步,需要子线程完成后主动调用本来需要父线程要执行的逻辑。父线程"盯的"是子线程返回的结果Future对象,抛开线程,那我们关注的是Future这个对象,将它作为Subject主题的实现,那么这个Future应该具备管理观察者列表,唤醒观察者。
ChannelFuture整合Future和通道
public interface ChannelFuture extends Future<Void> {
Channel channel();
@Override
ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);
@Override
ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
@Override
ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> listener);
}
DefaultChannelPromise,整合通道和Future以及promise
手动控制异步完成时机。
public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
private final Channel channel;
@Override
protected EventExecutor executor() {
EventExecutor e = super.executor();
if (e == null) {
return channel().eventLoop();
} else {
return e;
}
}
//手动控制异步操作的完成时机时
@Override
public ChannelPromise setSuccess(Void result) {
super.setSuccess(result);
return this;
}
}
到此被观察者已经可以管理观察者列表(add,remove),还能唤醒执行观察者的应对事件发生的逻辑
Obsrve->Listener
通道读结束之后,关闭当前通道返回一个ChannelFutrue,此时将关闭父通道的逻辑注册到ChannelFutrue上,我们不用等待通道关闭返回结果。通道读写就结束了。
public interface EventListener {
}
public interface GenericFutureListener<F extends Future<?>> extends EventListener {
void operationComplete(F future) throws Exception;
}
//源码测试中的例子,在请求关闭通道时,会注册关闭父通道的监听
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buffer = (ByteBuf) msg;
received += buffer.readableBytes();
buffer.release();
if (received == bufferSize) {//ctx.close()关闭通道,返回所关闭的通道实例
ctx.close().addListener((ChannelFuture future) -> {
// Close the underlying QuicChannel as well.
future.channel().parent().close();
});
}
}
监听触发:
当前线程是EventLoop线程 → 直接同步执行关闭操作
如果不是 EventLoop 线程 → 提交任务到线程池,异步执行关闭操作
4.1虽然是同步执行的关闭,该机制仍属于 Netty 异步非阻塞模型的一部分,因为它通过
Promise监听器解耦了操作的触发和结果处理,确保了线程安全和高效执行。
public ChannelFuture close(final ChannelPromise promise) {
// 1. 检查 Promise 有效性
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
// 2. 找到下一个 Outbound 处理器上下文(支持关闭操作)
final AbstractChannelHandlerContext next = findContextOutbound(MASK_CLOSE);
// 3. 获取关联的 EventLoop(线程池)
EventExecutor executor = next.executor();
// 4. 判断当前线程是否是 EventLoop 线程
if (executor.inEventLoop()) {
// 4.1 如果是EventLoop线程 → 直接同步执行关闭操作
next.invokeClose(promise);
} else {
// 4.2 如果不是EventLoop线程 → 提交任务到线程池,异步执行关闭操作
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeClose(promise);
}
}, promise, null, false);
}
return promise;
}
// 通道关闭的核心实现,处理关闭流程的各个阶段
protected void close(final ChannelPromise promise, // 用于通知关闭结果的Promise对象
final Throwable cause, // 导致关闭的异常(用于失败刷新消息)
final ClosedChannelException closeCause) { // 通道关闭专用异常
// 1. 设置Promise不可取消,确保关闭流程必须执行完成
if (!promise.setUncancellable()) {
return; // 如果已经被取消,直接返回
}
// 2. 处理重复关闭请求(幂等性处理)
if (closeInitiated) {
if (closeFuture.isDone()) {
// 如果已经关闭完成,直接设置Promise成功
safeSetSuccess(promise);
} else if (!(promise instanceof VoidChannelPromise)) {
// 非空Promise需要等待现有关闭操作完成
closeFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
promise.setSuccess(); // 继承现有关闭操作的结果
}
});
}
return;
}
// 3. 标记关闭流程开始(原子操作)
closeInitiated = true;
// 4. 保存通道状态和缓冲区引用
final boolean wasActive = isActive(); // 记录关闭前的活跃状态
final ChannelOutboundBuffer outboundBuffer = this.outboundBuffer; // 获取待发送消息缓冲区
this.outboundBuffer = null; // 禁止继续写入新消息(防止并发操作)
// 5. 准备关闭执行器(某些传输层需要特殊线程执行关闭)
Executor closeExecutor = prepareToClose();
if (closeExecutor != null) {
// 6. 需要特殊执行器的情况(如NIO需要Selector线程)
closeExecutor.execute(new Runnable() {
@Override
public void run() {
try {
// 7. 执行底层关闭操作(如Socket.close())
doClose0(promise);
} finally {
// 8. 确保后续操作回到EventLoop线程
invokeLater(new Runnable() {
@Override
public void run() {
// 9. 处理未发送消息(重要:失败排队中的消息)
if (outboundBuffer != null) {
outboundBuffer.failFlushed(cause, false); // 标记已flush的消息失败
outboundBuffer.close(closeCause); // 关闭缓冲区并释放资源
}
// 10. 触发通道非激活事件并注销
fireChannelInactiveAndDeregister(wasActive);
}
});
}
}
});
} else {
// 11. 普通关闭流程(当前线程执行)
try {
doClose0(promise); // 直接执行底层关闭
} finally {
// 12. 无论是否异常都要处理缓冲区
if (outboundBuffer != null) {
outboundBuffer.failFlushed(cause, false);
outboundBuffer.close(closeCause);
}
}
// 13. 处理flush过程中的特殊状态
if (inFlush0) { // 如果当前正在执行flush操作
// 延迟触发事件到flush完成后
invokeLater(new Runnable() {
@Override
public void run() {
fireChannelInactiveAndDeregister(wasActive);
}
});
} else {
// 立即触发通道状态变更
fireChannelInactiveAndDeregister(wasActive);
}
}
}
// 实际的底层关闭操作封装
private void doClose0(ChannelPromise promise) {
try {
doClose(); // 抽象方法,由具体传输实现(如NioSocketChannel)
closeFuture.setClosed(); // 设置关闭Future状态
safeSetSuccess(promise); // 通知关闭成功
} catch (Throwable t) {
// 异常处理:记录日志并通知Promise
closeFuture.setClosed();
safeSetFailure(promise, t); // 传播异常给调用方
}
}
总结
- netty中IO操作(bind,read,write,connect等)会立即返回ChannelFuture
- 向ChannelFuture中注册监听(GenericFutureListener),IO执行结束回调它的operationComplete方法