分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 前端开发

【Netty】(3)—源码NioEventLoopGroup

发布时间:2023-09-06 02:25责任编辑:彭小芳关键词:暂无标签

netty(3)—源码NioEventLoopGroup

一、概念

NioEventLoopGroup对象可以理解为一个线程池,内部维护了一组线程,每个线程负责处理多个Channel上的事件,而一个Channel只对应于一个线程,这样可以回避多线程下的数据同步问题。

我们先回顾下 上篇博客的服务器代码

 ???????// 定义一对线程组 ???????// 主线程组, 用于接受客户端的连接,但是不做任何处理,跟老板一样,不做事 ???????EventLoopGroup bossGroup = new NioEventLoopGroup(); ???????// 从线程组, 老板线程组会把任务丢给他,让手下线程组去做任务 ???????EventLoopGroup workerGroup = new NioEventLoopGroup(); ???????????????// netty服务器的创建, 辅助工具类,用于服务器通道的一系列配置 ???????ServerBootstrap serverBootstrap = new ServerBootstrap(); ???????serverBootstrap.group(bossGroup, workerGroup) ??????????//绑定两个线程组 ??????????????????????????//省略......

职责:

  1. 作为服务端 Acceptor 线程,负责处理客户端的请求接入。
  2. 作为客户端 Connector 线程,负责注册监听连接操作位,用于判断异步连接结果。
  3. 作为IO 线程,监听网络读操作位,负责从 SocketChannel 中读取报文。
  4. 作为 IO 线程,负责向 SocketChannel 写入报文发送给对方,如果发生写半包,会自动注册监听写事件,用 于后续继续发送半包数据,直到数据全部发送完成。
  5. 作为定时任务线程,可以执行定时任务,例如链路空闲检测和发送心跳消息等。
  6. 作为线程执行器可以执行普通的任务线程(Runnable)。


二、NioEventLoopGroup源码分析

上面的代码 创建bossGroup及workerGroup时,使用了NioEventLoopGroup的无参构造方法,本篇将从此无参构造入手,详细分析NioEventLoopGroup的初始化过程。

 ???/** ????* 1、首先我们看看NioEventLoopGroup的无参构造方法: ????* 作用:线程数为0 ????*/ ???public NioEventLoopGroup() { ???????this(0); ???} ???/** ????* 2、继续调用构造函数。 ????* 作用:指定线程为0,且Executor为null ????*/ ???public NioEventLoopGroup(int nThreads) { ???????this(nThreads, (Executor) null); ???} ???/** ????* 3、继续调用构造函数 ????* 作用:此构造方法它会指定selector的辅助类 "SelectorProvider.provider()" ????*/ ???public NioEventLoopGroup(int nThreads, Executor executor) { ???????this(nThreads, executor, SelectorProvider.provider()); ???} ???/** ????* 4、继续调用构造函数 ????* 作用:初始化了一个默认的选择策略工厂,用于生成select策略 ????*/ ???public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider) { ???????this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE); ???} ???/** ????* 5、继续调用构造函数 ????* 作用:指定拒绝策略:RejectedExecutionHandlers.reject() ????*/ ???public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,final SelectStrategyFactory selectStrategyFactory) { ???????super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()); ???}

经过上面一系列的构造方法调用,此时参数值对应如下:

  1. ? nThreads: 0
  2. ? executor: null
  3. ? selectorProvider: SelectorProvider.provider()
  4. ? selectStrategyFactory: DefaultSelectStrategyFactory.INSTANCE
  5. ? 以及指定了拒绝策略: RejectedExecutionHandlers.reject()
 ???/** ????* 6、从这里开始 调用父类 MultithreadEventLoopGroup 的构造函数 ????* 作用: 就是当指定的线程数为0时,使用默认的线程数DEFAULT_EVENT_LOOP_THREADS, ????* ?????而DEFAULT_EVENT_LOOP_THREAD是在静态代码块中就被执行。 ????*/ ???protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { ???????super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); ???} ???/** ????* 6.1 我们看下静态代码块 ????* 作用:到这一步得出关键的一点:`如果初始化NioEventLoopGroup未指定线程数,默认是CPU核心数*2`。 ????*/ ???private static final int DEFAULT_EVENT_LOOP_THREADS; ???static { ???????DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( ???????????????"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)) ???} ???/** ????* 7、继续调用父类 MultithreadEventLoopGroup 构造函数 ????* 作用:指定了一个EventExecutor的选择工厂DefaultEventExecutorChooserFactory, ????* ?????此工厂主要是用于选择下一个可用的EventExecutor ????*/ ???protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) { ???????this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args); ???} ???/** ????* 8、继续调用父类 MultithreadEventLoopGroup 构造函数 这里就是核心代码 删除部分非核心代码 ????* ???作用单独分析 ????*/ ???protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { ???????//1、 ???????//executor校验非空, 如果为空就创建ThreadPerTaskExecutor, 该类实现了 Executor接口 ???????// 这个executor 是用来执行线程池中的所有的线程,也就是所有的NioEventLoop,其实从 ???????//NioEventLoop构造器中也可以知道,NioEventLoop构造器中都传入了executor这个参数。 ???????if (executor == null) { ???????????executor = new ThreadPerTaskExecutor(newDefaultThreadFactory()); ???????} ???????//2、 ???????//这里的children数组, 其实就是线程池的核心实现,线程池中就是通过指定的线程数组来实现线程池; ???????//数组中每个元素其实就是一个EventLoop,EventLoop是EventExecutor的子接口。 ???????children = new EventExecutor[nThreads]; ???????//for循环实例化children数组,NioEventLoop对象 ???????for (int i = 0; i < nThreads; i++) { ???????????boolean success = false; ???????????//3、 ???????????//newChild(executor, args) 函数在NioEventLoopGroup类中实现了, ???????????// 实质就是就是存入了一个 NIOEventLoop类实例 ???????????children[i] = newChild(executor, args); ???????????success = true; ???????} ???????//4、实例化线程工厂执行器选择器: 根据children获取选择器 ???????chooser = chooserFactory.newChooser(children); ???????//5、为每个EventLoop线程添加 线程终止监听器 ???????final FutureListener<Object> terminationListener = new FutureListener<Object>() { ???????????@Override ???????????public void operationComplete(Future<Object> future) throws Exception { ???????????????if (terminatedChildren.incrementAndGet() == children.length) { ???????????????????terminationFuture.setSuccess(null); ???????????????} ???????????} ???????}; ???????//6、将children 添加到对应的set集合中去重, 表示只可读。 ???????Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length); ???????Collections.addAll(childrenSet, children); ???????readonlyChildren = Collections.unmodifiableSet(childrenSet); ???}}/** * 8.3.1 我们再来看下 newChild(executor, args) 里的方法 * 我们可以看到 返回的就是一个 NioEventLoop */@Overrideprotected EventLoop newChild(Executor executor, Object... args) throws Exception { ???return new NioEventLoop(this, executor, (SelectorProvider) args[0], ???????????((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);}

我们再回顾总结一下:

  1. NioEventLoopGroup初始化时未指定线程数,那么会使用默认线程数,即 线程数 = CPU核心数 * 2
  2. 每个NioEventLoopGroup对象内部都有一组可执行的NioEventLoop数组,一个NIOEventLoop可以理解成就是一个线程。
  3. 所有的NIOEventLoop线程是使用相同的 executor、SelectorProvider、SelectStrategyFactory、RejectedExecutionHandler以及是属于某一个NIOEventLoopGroup的。
    这一点从 newChild(executor, args); 方法就可以看出:newChild()的实现是在NIOEventLoopGroup中实现的。
  4. 当有IO事件来时,需要从线程池中选择一个线程出来执行,这时候的NioEventLoop选择策略是由GenericEventExecutorChooser实现的, 并调用该类的next()方法。
  5. 每个NioEventLoopGroup对象都有一个NioEventLoop选择器与之对应,其会根据NioEventLoop的个数,动态选择chooser(如果是2的幂次方,则按位运算,否则使用普通的轮询)

所以通过上面的分析,我们得出NioEventLoopGroup主要功能就是为了创建一定数量的NioEventLoop,而真正的重点就在NioEventLoop中,它是整个netty线程执行的关键。

有关NioEventLoop可以参考文章: [netty源码分析]--EventLoopGroup与EventLoop




如果一个人充满快乐,正面的思想,那么好的人事物就会和他共鸣,而且被他吸引过来。同样,一个人老带悲伤,倒霉的事情也会跟过来。 ?????????????????????????????????????????????????????——在自己心情低落的时候,告诫自己不要把负能量带给别人。(大校12)

【Netty】(3)—源码NioEventLoopGroup

原文地址:https://www.cnblogs.com/qdhxhz/p/10075568.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved