netty源码分析5-NioEventLoopGroup
分享内容如下:
- NioEventLoopGroup初始化分析
- NioEventLoopGroup父子类分析
- parentGroup与childGroup区别
1.NioEventLoopGroup初始化分析
从接口类图上看 EventLoopGroup 继承了 线程池和定时线程池功能,判断EventLoopGroup具有线程池的复合功能。从命名猜测 EventLoopGroup 管理了一组 EventLoop
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
//.......
//executor默认初始化类型为ThreadPerTaskExecutor
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//创建了length=8的EventExecutor组
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
// 返回NioEventLoop
//NioEventLoopGroup 覆盖了newChild方法
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
}
}
}
ThreadPerTaskExecutor分析
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//使用了新的ThreadFactory,为生成的线程增加线程名前缀。
线程名前缀规则: 类简名+“-”+ThreadFactory序号+“-”
如: nioEventLoopGroup-2-
后缀:从1开始每创建一次加入
完整线程名如下
nioEventLoopGroup-2-1
nioEventLoopGroup-2-2
nioEventLoopGroup的ThreadFactory序号是2
生成的线程 toString:Thread[nioEventLoopGroup-2-1,10,main] 其中nioEventLoopGroup-2-1是线程名,10是优先级策略,main是组名默认生成
因为io.netty.util.concurrent.GlobalEventExecutor 提前加载,其中字段调用了一次DefaultThreadFactory构造方法。
代码:private final ThreadFactory threadFactory = new DefaultThreadFactory(getClass());
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
//threadFactory赋值
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
}
this.threadFactory = threadFactory;
}
@Override
//使用threadFactory创建线程
public void execute(Runnable command) {
threadFactory.newThread(command).start(); //生成新线程,并以单线程执行 command
}
}
这里需要 注意 ThreadPerTaskExecutor.execute(Runnable command) 是以单线程运行的。NioEventLoop启动 调用了这个方法。
小结:ThreadPerTaskExecutor使用了新的ThreadFactory,为生成的线程增加线程名前缀。
实现了创建新线程,并以单线程执行 Runnable 的execute方法。
EventLoopGroup 中重要的两个方法,newChild()和next(),代码如下。
NioEventLoopGroup-newChild()
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0]);
}
}
newChild:创建NioEventLoop
NioEventLoopGroup只有这个一个覆盖方法。创建NioEventLoop
MultithreadEventExecutorGroup-next()
@Override
public EventExecutor next() {
return children[Math.abs(childIndex.getAndIncrement() % children.length)];
}
next:轮询获取从Reactor线程组的NioEventLoop
小结:NioEventLoopGroup初始化最主要的任务是创建了NioEventLoop数组。
2.NioEventLoopGroup父子类分析
主要的接口类图如下
EventExecutorGroup:next 获取EventExecutor, 线程任务执行, 定时任务
EventExecutor:多了newPromise,inEventLoop();
EventLoopGroup:只有EventLoop next();
EventLoop:只有以下3个方法
EventLoopGroup parent();//暂时不分析
EventLoop next();//看了其实现类 都是return this
ChannelHandlerInvoker asInvoker();//返回一个包装handler执行的invoker,默认使用
分析NioEventLoopGroup中的父子类
NioEventLoopGroup类图如下
AbstractEventExecutorGroup:next 获取EventExecutor未实现。线程任务执行, 定时任务都是 next().xxx()
MultithreadEventExecutorGroup:类注释的意思是多线程方式处理任务,从代码实现上来看,没有多线程的处理,主要功能是维护EventExecutor数组,实现了next()。
主要方法如下
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
//.......
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
//创建size()=nThreads的线程组
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
} finally {
//......
}
}
//重要:实现了next获取EventExecutor
public EventExecutor next() {
return children[Math.abs(childIndex.getAndIncrement() % children.length)];
}
//由子类实现
protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;
MultithreadEventLoopGroup:类注释无参照意义。主要功能是获取默认的线程数,/重写next返回类型为EventLoop
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
//获取默认的线程数
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
}
//重写next返回类型为EventLoop
public EventLoop next() {
return (EventLoop) super.next();
}
newChild 还是没有实现
NioEventLoopGroup:
主要方法如下
//设置 希望child event loops 占用IO线程执行与执行任务的百分比。默认值是50, 此时I/O 和 non-I/O 将会试图占用相同的时间。
public void setIoRatio(int ioRatio) {
for (EventExecutor e: children()) {
((NioEventLoop) e).setIoRatio(ioRatio);
}
}
//替换原来的Selector,处理著名的epoll 100% bug,依赖NioEventLoop实现
public void rebuildSelectors() {
for (EventExecutor e: children()) {
((NioEventLoop) e).rebuildSelector();
}
}
//重写 newChild,创建NioEventLoop
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0]);
}
小结:NioEventLoopGroup主要功能是维护EventExecutor数组,实现了next(),暴露了一些线程,工具类方法, 都是依赖NioEventLoop实现。
3.parentGroup与childGroup区别
parentGroup是Reactor模式中主Reactor线程组,childGroup是从Reactor线程组。
怎么区分,当客户端发起连接时,服务需要获取相应的连接与之通讯,此时childGroup发挥作用。
这时会调用AbstractNioMessageChannel$NioMessageUnsafe.read() ,它理解 5.0.0版本parentGroup和childGroup的重要点
public void read() {
//...............................
try {
for (;;) {// 此处用到了循环,有可能 同时有2个以上的客户端发起连接
int localRead = doReadMessages(readBuf);代码A
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
if (readBuf.size() >= maxMessagesPerRead | !autoRead) {
break;
}
}
} catch (Throwable t) {
exception = t;
}
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
pipeline.fireChannelRead(readBuf.get(i));代码B
}
readBuf.clear();
pipeline.fireChannelReadComplete();
//..............................................
}
代码A获取原生SocketChannel,使用childGroup中EventLoop 后创建了NioSocketChannel,使用。
代码B触发ChannelRead事件,最后执行了注册,启动了NioSocketChannel的EventLoop 线程。
这个方法中 获取并启动了 childGroup中的NioEventLoop
小结:server端在接受连接后创建了NioSocketChannel,注册在ChildGroup上,由此可推测,parentGroup负责接受客户端链接,childGroup负责IO操作。
总结:NioEventLoopGroup 管理了一组 NioEventLoop,parentGroup负责接受客户端链接,childGroup负责IO操作。
netty源码分析5-NioEventLoopGroup相关推荐
- Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用
Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用 Netty源码分析第一章:Netty启动流程 第四节:注册多路复用 回顾下以上的小节, 我们知道了channe ...
- 【Netty源码分析摘录】(八)新连接的接入
文章目录 1.问题 2.检测新连接接入 3.创建客户端 channel 4. 绑定 NioEventLoop 4.1 register0 4.1.1 doRegister() 4.1.2 pipeli ...
- Netty源码分析第6章(解码器)----第4节: 分隔符解码器
Netty源码分析第6章(解码器)---->第4节: 分隔符解码器 Netty源码分析第六章: 解码器 第四节: 分隔符解码器 基于分隔符解码器DelimiterBasedFrameDecode ...
- Netty源码分析第7章(编码器和写数据)----第2节: MessageToByteEncoder
Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEnc ...
- Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述
Netty源码分析第5章(ByteBuf)---->第5节: directArena分配缓冲区概述 Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上 ...
- Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...
- Netty源码分析(六)—Future和Promis分析
Netty源码分析(六)-Future和Promis分析 Future用来在异步执行中获取提前执行的结果 个人主页:tuzhenyu's page 原文地址:Netty源码分析(六)-Future和P ...
- Netty源码分析系列之服务端Channel的端口绑定
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 微信公众号 问题 本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Ne ...
- netty源码分析系列——EventLoop
2019独角兽企业重金招聘Python工程师标准>>> 前言 EventLoop也是netty作为一个事件驱动架构的网络框架的重要组成部分,netty主要通过它来实现异步编程,从前面 ...
- Netty 源码分析系列(十五)自定义解码器、编码器、编解码器
前言 我们今天继续来分析 Netty 的编解码器,这次我们要自己动手实现自定义的编码器.解码器和编解码器. 自定义基于换行的解码器 LineBasedFrameDecoder 类 LineBasedF ...
最新文章
- Verilog testbench总结(二)
- Windows 窗体设计器中的设计时错误
- c++17进阶(3)-Boehm GC垃圾回收(1)
- 1109: 胥哥的DOTA-水题(直接做,时间也不超限)
- swagger api文档_带有Swagger的Spring Rest API –创建文档
- 前端学习(2854):简单秒杀系统学习之settimeout
- Spring简洁总结
- 结合内存分析java归并排序_排序算法之归并排序(Mergesort)解析
- (https)nginx - tomcat(http)
- Spring,FetchType.LAZY和FetchType.EAGER什么区别?
- 【SQL】日期型函数
- java面试基础_java面试之基础(总结)
- (一)Flask 学习 —— Hello World
- 桂林理工大学 大学语文题库2021年春季学期
- MATLAB必看书籍推荐
- STM32F103C8T6详细引脚表
- php 半角 全角空格,全角空格和半角空格
- Redis过期策略---实现原理
- 【网络】远程连接路由器
- java 7 反射_【7】java 反射详解
热门文章
- 从数据结构到python编程
- RK3288:linux系统中基于I2C的数字温度传感器TCN75A的驱动调试
- 算法ppt练习题(给黄成个大逼兜)
- (遇到问题)ubuntu遇到文件夹带锁如何去除,已解决
- Linux如何去掉文件夹的锁
- “青海年·醉海东”系列活动启幕 多民族“共烹”河湟文化年
- 321酷生活导航第一期:AIDN(js和flash类的小游戏)
- iOS_青花瓷Charles抓包
- 智能投影机android系统,投影仪内置安卓系统的好吗?当贝OS有多强?
- 郑商所比赛交易日志1