通过以下这行代码创建SubReactor线程组,也就是NioEventLoop线程组;
构造一个SelectorProvider.provider()
,这个provider就负责创建每个NioEventLoop维护的selector,同时初始化一个默认选择器执行策略
传入一个默认的线程选择器
创建一个默认的ThreadPerTaskExecutor,每次执行任务的时候都会创建一个线程,初始化是通过DefaultThreadFactory来创建的;
每次调用execute方法都会创建一个线程
构造DefaultThreadFactory,初始化线程的名称前缀
初始化NioEventLoop线程的名称前缀
创建线程的时候会将这个线程名传入对应的构造函数
netty中对jdk的Thread做了一层封装
创建NioEventLoop
代码在io.netty.channel.nio.NioEventLoopGroup#newChild这里实现,args参数如下
构造函数中设置executor,线程拒绝策略,taskQueue等
taskQueue:外部线程在执行netty的任务的时候,如果判断不是在NioEventLoop对应的线程里面去执行,这些任务会直接丢到一个任务队列中,然后由NioEventloop对应的线程去执行过程,初始化调用jdk底层初始化一个mscpQueue
mpscQueue(multi producer single consumer),multi producer对应的就是非Nio线程,Single consumer 就是netty的一个NioEventLoop线程,也就是说外部线程可以丢进来,由一个NioEventLoop去消费
最后就是绑定selector操作,注意看,其实每一个NioEventLoop都有一个对应的selector
最后创建EventExecutorChooser,chooser其实就是给新链接绑定NioEventLoop
NioEventLoop启动,通过dobind0方法新起一个Runnable进行端口绑定
什么时候channel绑定的NioEventLoop嘞?在这个地方实现的netty通过java.nio.channels.SelectableChannel#register(java.nio.channels.Selector, int, java.lang.Object)
方法将自身实现的NioSocketChannel和SelectionKey,原生的socket channel绑定在了一起
接下来看下execute方法,代码实现在io.netty.util.concurrent.SingleThreadEventExecutor#execute
,这里inEventLoop
返回false,所以就会启动一个新线程,并往TaskQueue添加任务
判断是不是NioEventLoop,这时候SingleThreadEventExecuto中的Thread的null,肯定不是当前主线程
启动线程,通过CAS判断当前线程是不是未启动的
接下来调用executor新建一个线程
首先保存当前线程,其实也就是将NioEventLoop与这个thread进行绑定
然后调用run方法进行实际的启动,其实这才是NioEventLoop的真实启动。
接下来就进入了NioEventLoop的run方法的执行了,这个我们后面再分析。