netty的Promise源码分析
netty 使用 DefaultPromise
完成异步操作,它对 jdk 的 Future 进行了扩展,提供了更丰富的功能。
DefaultPromise 的结构
DefaultPromise 的类继承结构如下图所示
最顶层的接口是 jdk 的 Future,它用于代表异步操作的结果,netty 对其进行了扩展
io.netty.util.concurrent.Future
io.netty.util.concurrent.Future
对 jdk 的 Future
进行了增强,它增加了如下方法
主要可以分为以下几类:
- 获取执行的结果状态。是否执行成功、是否取消、获取异常信息
- 添加、移除 Listener,用于监听执行成功事件并做响应处理
- 同步等待执行完成
getNow
获取执行结果,非阻塞操作,若无结果则返回 null
io.netty.util.concurrent.AbstractFuture
AbstractFuture
是 Future
的一个抽象实现类,它提供了 get
方法的实现
1 | public V get() throws InterruptedException, ExecutionException { |
io.netty.util.concurrent.Promise
Promise
继承了 Future
,它用于表示支持写操作的 Future
它相对于 Future 主要增加了设置执行结果的方法
- 设置执行成功的结果。setSuccess、trySuccess
- 设置执行失败的结果。setFailure、tryFailure
- 标记 Future 不能取消。setUncancellable
io.netty.util.concurrent.DefaultPromise
DefaultPromise
是 Promise
的一个默认实现类,它的主要属性如下
1 | // 执行的结果,使用volatile修饰,保证可见性 |
从属性中可以看出,DefaultPromise
使用了 Object 的 wait/notiry 机制
DefaultPromise 分析
接下来我们来看下它是怎么工作的,如下是一段示例代码
1 | // 创建一个 Promise |
这里创建了一个 DefaultPromise
示例,并且在一个异步线程中设置执行成功。此外往 DefaultPromise
中添加了一个 listener,当其执行完之后输出一行日志。如下是执行的结果
1 | before thread start |
可以看到,当异步线程执行为 future 设置完执行结果之后,才触发了 listener 的执行
调用链路
当执行完 future.trySuccess(null)
这行代码时,最终会往 GlobalEventExecutor.INSTANCE
中添加一个任务,它的调用栈如下
1 | // 1. DefaultPromise#trySuccess |
注意第 6 步,添加完任务后,因为当前并不是在 eventloop 线程中执行,所以会执行 startThread 启动线程。
此时该线程会从任务队列中获取任务执行,因而会获取到第 4 步添加到 exector 中 Runnable 任务 notifyListenersNow
,它的调用栈如下:
notifyListenersNow
最终调用 notifyListener0
通知注册的 listener
1 | // DefaultPromise#notifyListener0 |
总结
DefaultPromise
通过 Object 的 wait/notify 机制实现线程间的同步,通过 volatile 属性保证线程间的可见性
DefaultPromise
支持注册 listener,当任务执行完成时通知 listener,这采用的是设计模式中的观察者模式。
DefaultPromise
需设置 Executor,当通知 listener 时,不是在主线程中执行,而是在 Executor 中执行
- 2021-01-28
如果你使用过 netty,你一定见过下面两行代码,它们可以说是创建一个 netty server 的标配代码
1
2ChannelFuture future = bootstrap.bind(port).sync();
future.channel().closeFuture().sync();不知道你有没想过这里面的
sync()
的作用是什么,如果去掉会有什么问题? - 2021-02-05
netty 是一个基于异步事件驱动实现的网络编程框架,它的内部使用了大量的异步编程方法,这是它性能高效的一个原因,但同时也使得代码阅读起来更加困难,本文就尝试分析下它的启动过程
- 2021-08-12
在使用 netty 开发网络应用时,通常会设置
ChannelOption.SO_BACKLOG
,不知你有没想过这个参数的作用是什么。 - 2021-11-26
今天在解决一个问题时,需要测下某机器的指定端口是否能正常接收数据,忽然发现想不起来命令叫啥(就是nc),看来还是要做好记录。考虑到后续可能还会添加新的命令,还要方便查阅和分享,索性就记到这里吧。
- 2021-01-02
netty 中的 channel 在完成创建和初始化之后,需要注册到 EventLoopGroup 上,这本质上是交给 EventLoop 管理 channel 的各种事件。一个 EventLoopGroup 管理了多个 EventLoop,那么在注册 channel 时,EventLoopGroup 就需要选择一个 EventLoop,然后将其和 channel 关联起来。选择 EventLoop 是一个很高频的操作,该操作是否高效会直接影响 netty 的性能,本文就来聊下 EventLoop 的选择策略。