原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注

今天是猿灯塔“365篇原创计划”第六篇。

接下来的时间灯塔君持续更新Netty系列一共九篇
 
Netty 源码解析(一 ):开始
Netty 源码解析(二): Netty 的 Channel
Netty 源码解析(三): Netty 的 Future 和 Promise
Netty 源码解析(四): Netty 的 ChannelPipeline
Netty 源码解析(五): Netty 的线程池分析
当前:Netty 源码解析(六): Channel 的 register 操作
Netty 源码解析(七): NioEventLoop 工作流程
Netty 源码解析(八): 回到 Channel 的 register 操作
Netty 源码解析(九): connect 过程和 bind 过程分析
今天呢!灯塔君跟大家讲:
Channel 的 register 操作

Channel 的 register 操作

接下来,我们来分析 Netty 中的线程池。Netty 中的线程池比较不好理解,因为它的类比较多,而且它们之间的关系错综复杂。看下图,感受下 NioEventLoop 类和 NioEventLoopGroup 类的继承结构:经过前面的铺垫,我们已经具备一定的基础了,我们开始来把前面学到的内容揉在一起。这节,我们会介绍 register 操作,这一步其实是非常关键的,对于我们源码分析非常重要。我们从 EchoClient 中的 connect() 方法出发,或者 EchoServer 的 bind(port) 方法出发,都会走到 initAndRegister() 这个方法:
 final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 1
channel = channelFactory.newChannel();
// 2 对于 Bootstrap 和 ServerBootstrap,这里面有些不一样
init(channel);
} catch (Throwable t) {
...
}
// 3 我们这里要说的是这行
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
initAndRegister() 这个方法我们已经接触过两次了,前面介绍了 1️⃣ Channel 的实例化,实例化过程中,会执行 Channel 内部 Unsafe 和 Pipeline 的实例化,以及在上面 2️⃣ init(channel) 方法中,会往 pipeline 中添加 handler(pipeline 此时是 head+channelnitializer+tail)。
我们这节终于要揭秘 ChannelInitializer 中的 initChannel 方法了~~~
现在,我们继续往下走,看看 3️⃣ register 这一步:
ChannelFuture regFuture = config().group().register(channel);
我们说了,register 这一步是非常关键的,它发生在 channel 实例化以后,大家回忆一下当前 channel 中的一些情况:实例化了 JDK 底层的 Channel,设置了非阻塞,实例化了 Unsafe,实例化了 Pipeline,同时往 pipeline 中添加了 head、tail 以及一个 ChannelInitializer 实例。
上面的 config().group() 方法会返回前面实例化的 NioEventLoopGroup 的实例,然后调用其 register(channel) 方法:// MultithreadEventLoopGroup
1@Override
2public ChannelFuture register(Channel channel) {
3 return next().register(channel);
4}
next() 方法很简单,就是选择线程池中的一个线程(还记得 chooserFactory 吗),也就是选择一个 NioEventLoop 实例,这个时候我们就进入到 NioEventLoop 了。NioEventLoop 的 register(channel) 方法实现在它的父类 SingleThreadEventLoop 中:
@Override
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
上面的代码实例化了一个 Promise,将当前 channel 带了进去:
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
// promise 关联了 channel,channel 持有 Unsafe 实例,register 操作就封装在 Unsafe 中
promise.channel().unsafe().register(this, promise);
return promise;
}
拿到 channel 中关联的 Unsafe 实例,然后调用它的 register 方法:
我们说过,Unsafe 专门用来封装底层实现,当然这里也没那么“底层”
// AbstractChannel#AbstractUnsafe
 @Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
...
// 将这个 eventLoop 实例设置给这个 channel,从此这个 channel 就是有 eventLoop 的了
// 我觉得这一步其实挺关键的,因为后续该 channel 中的所有异步操作,都要提交给这个 eventLoop 来执行
AbstractChannel.this.eventLoop = eventLoop; // 如果发起 register 动作的线程就是 eventLoop 实例中的线程,那么直接调用 register0(promise)
// 对于我们来说,它不会进入到这个分支,
// 之所以有这个分支,是因为我们是可以 unregister,然后再 register 的,后面再仔细看
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
// 否则,提交任务给 eventLoop,eventLoop 中的线程会负责调用 register0(promise)
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
...
}
}
到这里,我们要明白,NioEventLoop 中是还没有实例化 Thread 实例的。
这几步涉及到了好几个类:NioEventLoop、Promise、Channel、Unsafe 等,大家要仔细理清楚它们的关系。对于我们前面过来的 register 操作,其实提交到 eventLoop 以后,就直接返回 promise 实例了,剩下的register0 是异步操作,它由 NioEventLoop 实例来完成。我们这边先不继续往里分析 register0(promise) 方法,先把前面欠下的 NioEventLoop 中的线程介绍清楚,然后再回来介绍这个 register0 方法。
Channel 实例一旦 register 到了 NioEventLoopGroup 实例中的某个 NioEventLoop 实例,那么后续该 Channel 的所有操作,都是由该 NioEventLoop 实例来完成的。这个也非常简单,因为 Selector 实例是在 NioEventLoop 实例中的,Channel 实例一旦注册到某个 Selector 实例中,当然也只能在这个实例中处理 NIO 事件。

本章节就到这了,敬请期待!

365天干货不断微信搜索「猿灯塔」第一时间阅读,回复【资料】【面试】【简历】有我准备的一线大厂面试资料和简历模板

Netty 源码解析(六): Channel 的 register 操作的更多相关文章

  1. Netty 源码解析(八): 回到 Channel 的 register 操作

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  2. Netty 源码解析(二):Netty 的 Channel

    本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty源码解析(一):开始 当前:Netty 源码解析(二): Netty 的 Channel ...

  3. Netty 源码解析(三): Netty 的 Future 和 Promise

    今天是猿灯塔“365篇原创计划”第三篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel 当前:Ne ...

  4. Netty 源码解析(九): connect 过程和 bind 过程分析

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第九篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  5. Netty 源码解析(七): NioEventLoop 工作流程

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第七篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  6. Netty 源码解析(五): Netty 的线程池分析

    今天是猿灯塔“365篇原创计划”第五篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...

  7. Netty 源码解析(四): Netty 的 ChannelPipeline

    今天是猿灯塔“365篇原创计划”第四篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...

  8. Netty源码解析—客户端启动

    Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ...

  9. Netty源码解析---服务端启动

    Netty源码解析---服务端启动 一个简单的服务端代码: public class SimpleServer { public static void main(String[] args) { N ...

随机推荐

  1. Java中构造方法的详细介绍

    构造方法是一个特殊的方法 它会在实例化对象时自动调用 构造方法的定义 必须同时满足下面的三个条件 方法名与类名相同 方法名前面没有返回值类型的声明 在方法中不能使用return语句返回值 class ...

  2. Java实现 蓝桥杯 算法提高 Monday-Saturday质因子

    试题 算法提高 Monday-Saturday质因子 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 这个问题是个简单的与数论有关的题目,看起来似乎是"求正整数的所有质因子 ...

  3. 体验SpringBoot(2.3)应用制作Docker镜像(官方方案)

    关于<SpringBoot-2.3容器化技术>系列 <SpringBoot-2.3容器化技术>系列,旨在和大家一起学习实践2.3版本带来的最新容器化技术,让咱们的Java应用更 ...

  4. LNMP zabbix 4.4

    硬件配置需求 环境 平台 CPU/内存 数据库 硬盘 监控主机数 小型 CentOS 2CPU/1GB MySQL.InnoDB 普通 100 中型 CentOS 2CPU/2GB MySQL.Inn ...

  5. 计算从1到n中,出现某位数字的次数

    出现1-9中某位数字次数的算法 /** * @param input 整数n(1 ≤ n ≤ 1,000,000,000) * @return 1-9中某个数字在数列中出现的次数 */ public ...

  6. 小谢第23问: chorme的性能优化工具

    问题场景:在前端日趋工程化的今天,前端性能优化是一名合格的前端工程师必备的技能,那么,如何正确的使用性能分析工具呢? 解决方案: 性能分析的流程: 在开发中我一般使用公司开发的测试脚本-kbase-w ...

  7. Python基础——爬虫以及简单的数据分析

    目标:使用Python编写爬虫,获取链家青岛站的房产信息,然后对爬取的房产信息进行分析. 环境:win10+python3.8+pycharm Python库: import requests imp ...

  8. OKR-Periods of Words【KMP最小前后缀】

    OKR-Periods of Words 传送门:链接    来源:UPC 8180 题目描述 串是有限个小写字符的序列,特别的,一个空序列也可以是一个串.一个串P是串A的前缀,当且仅当存在串B,使得 ...

  9. FastStone+ImageReady+Kutools plus导入图片到Excel单元格

    先前打算自己做一个也附带训练下,发现有下面方法也好. 1)做帮助文档时需要一种格式(需要将图片导入到Excel中时,假如是按此法归类汇总) 2)FastStone滚动截图       粘贴到Photo ...

  10. MFC基于CAsyncSocket套接字客户端代码示范

    MFC基于CAsyncSocket套接字客户端代码示范 https://blog.csdn.net/txwtech/article/details/93016190