netty源码分析5-NioEventLoopGroup

本文深入分析Netty中NioEventLoopGroup的初始化过程,探讨其父子类的区别与功能,以及parentGroup与childGroup在Reactor模式中的角色。通过源码解读,揭示NioEventLoopGroup如何管理一组NioEventLoop,parentGroup如何负责客户端连接,而childGroup则专注于IO操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享内容如下:

  1. NioEventLoopGroup初始化分析
  2. NioEventLoopGroup父子类分析
  3. 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操作。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值