EventLoop继承关系
1 | EventLoopGroup bossGroup = new NioEventLoopGroup(); |
NioEventLoopGroup
NioEventLoopGroup是一个NioEventLoop组,它有一个EventExecutor[] 成员变量,数组中的每一个元素是NioEventLoop类型的对象,所以NioEventLoopGroup可以看做是一系列NioEventLoop的集合。
NioEventLoopGroup初始化的时候可以指定线程数,如果没有指定,将获取系统可以的处理器数量*2作为线程数,这个线程数代表着NioEventLoopGroup可以有多少个NioEventLoop。
NioEventLoopGroup的构造函数中,有一个Executor类型的参数,默认使用ThreadPerTaskExecutor实现,因为NioEventLoop中也有一个Executor,暂且将这个NioEventLoopGroup的Executor称为全局的Executor,在实例化NioEventLoop的时候,传入了这个全局的Executor。
- ThreadPerTaskExecutor的execute方法会通过ThreadFactory线程工厂创建一个线程,并且启动该线程,EventLoop中就是通过它来创建线程的。
- 看到Executor首先会想起Java中的线程池,将需要执行的任务添加到线程池,由线程池管理并执行任务。
NioEventLoopGroup中有一个EventExecutorChooser选择器,因为EventExecutor[] 数组中有多个NioEventLoop对象,选择器就是来选择使用哪个NioEventLoop。
NioEventLoopGroup初始化
1 | public class NioEventLoopGroup extends MultithreadEventLoopGroup { |
MultithreadEventLoopGroup
1 | public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup { |
NioEventLoop
- NioEventLoop中包含了一个Selector
- NioEventLoop中有三种任务队列:
- 普通任务队列taskQueue,一些核心的任务就是放在taskQueue中的
- 定时任务队列scheduledTaskQueue,处理一些定时任务
- 收尾任务队列tailTasks,做一些收尾的工作
- 每个NioEventLoop中也有一个Executor,因为NioEventLoop是Executor的子类,所以NioEventLoop本身也是一个Executor
- ThreadExecutorMap中维护了线程和EventLoop的绑定关系,记录了每个线程绑定到了哪个EventLoop
1 | public final class NioEventLoop extends SingleThreadEventLoop { |
ThreadExecutorMap
ThreadExecutorMap中记录了每个线程绑定的EventLoop,从名字上也能看出,它记录的是Thread线程和Executor的对应关系。
1 | public final class ThreadExecutorMap { |
Channel初始化与注册
以Channel初始化与注册的过程为例,看一下EventLoop的使用:
回到AbstractBootstrap的initAndRegister初始化并注册Channel的方法,可以看到获取了EventLoopGroup,然后调用它的register方法进行注册。
EventLoopGroup的register实际上是通过选择器,从EventLoop数组中选择了一个EventLoop返回,最终调用EventLoop的register方法进行注册。
1 | // AbstractBootstrap |
AbstractChannel的register进行注册:
- 可以看到将当前的Channel绑定到了选择EventLoop上。
- 判断当前线程是否是NioEventLoop中的线程,首次启动注册Channel时,当前线程不是NioEventLoop的线程,所以会走到else的代码中,向EventLoop中添加了一个注册任务。
1 | public abstract class AbstractChannel extends DefaultAttributeMap implements Channel { |
SingleThreadEventExecutor
SingleThreadEventExecutor实现了execute方法,进行任务添加:
- 将需要执行的任务放到了taskQueue任务队列中
- 如果不是EventLoop线程(首次启动Channel不是EventLoop线程),调用startThread开启了一个线程,开启方式是通过调用EventLoop的executor,向线程池中执行任务,最终是通过EventLoopGroup的executor的execute方法会创建线程并且启动线程。
- 之前提到过EventLoop也是一个Executor,所以它本身也可以接受任务,实现了execute方法,这个方法就是在SingleThreadEventExecutor中实现的。
- EventLoop中有一个Executor的成员变量,它的execute方法是通过EventLoopGroup的Executor创建线程使用的。
- 将NioEventLoop的thread成员变量设置为当前获取到的线程,实现了当前线程与NioEventLoop的绑定
1 | //io.netty.util.concurrent.SingleThreadEventExecutor |
ThreadExecutorMap
在NioEventLoop实例化的时候可以知道,NioEventLoop的Executor是在ThreadExecutorMap中完成实例化的,所以调用NioEventLoop的Executor的execute方法就会进入ThreadExecutorMap中实例化Executor时重写的execute方法,在这个方法中,又会调用EventLoopGroup的executor创建线程并启动线程。
1 | public static Executor apply(final Executor executor, final EventExecutor eventExecutor) { |
总结:
到这里,应该已经知道EventLoop和EventLoopGroup的作用是什么了,再次总结一下:
1. NioEventLoopGroup是一个NioEventLoop组,里面包含多个NioEventLoop,可以看做是一系列NioEventLoop的集合
2. NioEventLoopGroup初始化会实例化一个Executor,它是用来创建线程使用的,可以看做是一个创建线程的线程池
3. NioEventLoopGroup会通过选择策略,类似于负载均衡算法从NioEventLoop数组中选取一个NioEventLoop
4.NioEventLoop中有三个任务队列,分别是taskQueue(处理普通任务)、tailTasks(收尾工作处理)和scheduledTaskQueue(定时任务队列)
5.NioEventLoop是Executor的子类,所以它本身也是一个Executor,可以向NioEventLoop中提交任务,任务提交后会添加到任务队列中等待处理
6.NioEventLoop中也有一个Executor,以成员变量的形式存在,它可以调用NioEventLoopGroup的Executor来创建线程,执行任务
Netty版本:4.1.42.Final
参考:
Netty(八)源码解析 之 NioEventLoopGroup和NioEventLoop源码分析、NioEventLoop绑定线程的流程分析