netty源码分析5-NioEventLoopGroup

分享内容如下:

  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操作。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastThreadLocal 是 Netty 中的一个优化版 ThreadLocal 实现。与 JDK 自带的 ThreadLocal 相比,FastThreadLocal 在性能上有所提升。 FastThreadLocal 的性能优势主要体现在以下几个方面: 1. 线程安全性:FastThreadLocal 使用了一种高效的方式来保证线程安全,避免了使用锁的开销,使得在高并发场景下性能更好。 2. 内存占用:FastThreadLocal 的内部数据结构更加紧凑,占用的内存更少,减少了对堆内存的占用,提高了内存的利用效率。 3. 访问速度:FastThreadLocal 在访问时,使用了直接索引的方式,避免了哈希表查找的开销,使得访问速度更快。 在 Netty 源码中,FastThreadLocal 主要被用于优化线程的局部变量存储,提高线程之间的数据隔离性和访问效率。通过使用 FastThreadLocal,Netty 在高性能的网络通信中能够更好地管理线程的局部变量,提供更高的性能和并发能力。 引用中提到的代码片段展示了 Netty 中的 InternalThreadLocalMap 的获取方式。如果当前线程是 FastThreadLocalThread 类型的线程,那么就直接调用 fastGet 方法来获取 InternalThreadLocalMap 实例;否则,调用 slowGet 方法来获取。 fastGet 方法中,会先尝试获取线程的 threadLocalMap 属性,如果不存在则创建一个新的 InternalThreadLocalMap,并设置为线程的 threadLocalMap 属性。最后返回获取到的 threadLocalMap。 slowGet 方法中,通过调用 UnpaddedInternalThreadLocalMap.slowThreadLocalMap 的 get 方法来获取 InternalThreadLocalMap 实例。如果获取到的实例为 null,则创建一个新的 InternalThreadLocalMap,并将其设置到 slowThreadLocalMap 中。最后返回获取到的 InternalThreadLocalMap。 综上所述,FastThreadLocal 是 Netty 中为了优化线程局部变量存储而设计的一种高性能的 ThreadLocal 实现。它通过减少锁的开销、优化内存占用和加快访问速度来提升性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FastThreadLocal源码分析](https://blog.csdn.net/lvlei19911108/article/details/118021402)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Netty 高性能之道 FastThreadLocal 源码分析(快且安全)](https://blog.csdn.net/weixin_33871366/article/details/94653953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值