Netty源码分析第2章(NioEventLoop)---->第3节: 初始化线程选择器
Netty源码分析第二章:NioEventLoop
第三节:初始化线程选择器
回到上一小节的MultithreadEventExecutorGroup类的构造方法:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
//代码省略
if (executor == null) {
//创建一个新的线程执行器(1)
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//构造NioEventLoop(2)
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
//代码省略
}
}
//创建线程选择器(3)
chooser = chooserFactory.newChooser(children);
//代码省略
}
我们看第三步, 创建线程选择器:
chooser = chooserFactory.newChooser(children);
NioEventLoop都绑定一个chooser对象, 作为线程选择器, 通过这个线程选择器, 为每一个channel分配不同的线程
我们看到newChooser(children)传入了NioEventLoop数组
我们跟到DefaultEventExecutorChooserFactory类中的newChooser方法:
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTowEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
这里通过 isPowerOfTwo(executors.length) 判断NioEventLoop的线程数是不是2的倍数, 然后根据判断结果返回两种选择器对象, 这里使用到java设计模式的策略模式
根据这两个类的名字不难看出, 如果是2的倍数, 使用的是一种高性能的方式选择线程, 如果不是2的倍数, 则使用一种比较普通的线程选择方式
我们简单跟进这两种策略的选择器对象中看一下, 首先看一下PowerOfTowEventExecutorChooser这个类:
private static final class PowerOfTowEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTowEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
这个类实现了线程选择器的接口EventExecutorChooser, 构造方法中初始化了NioEventLoop线程数组
重点关注下next()方法, next()方法就是选择下一个线程的方法, 如果线程数是2的倍数, 这里通过按位与进行计算, 所以效率极高
再看一下GenericEventExecutorChooser这个类:
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
这个类同样实现了线程选择器的接口EventExecutorChooser, 并在造方法中初始化了NioEventLoop线程数组
再看这个类的next()方法, 如果线程数不是2的倍数, 则用绝对值和取模的这种效率一般的方式进行线程选择
这样, 我们就初始化了线程选择器对象
上一节: NioEventLoopGroup之NioEventLoop的创建
Netty源码分析第2章(NioEventLoop)---->第3节: 初始化线程选择器的更多相关文章
- Netty源码分析第2章(NioEventLoop)---->第1节: NioEventLoopGroup之创建线程执行器
Netty源码分析第二章: NioEventLoop 概述: 通过上一章的学习, 我们了解了Server启动的大致流程, 有很多组件与模块并没有细讲, 从这个章开始, 我们开始详细剖析netty的各个 ...
- Netty源码分析第2章(NioEventLoop)---->第2节: NioEventLoopGroup之NioEventLoop的创建
Netty源码分析第二章: NioEventLoop 第二节: NioEventLoopGroup之NioEventLoop的创建 回到上一小节的MultithreadEventExecutorG ...
- Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动
Netty源码分析第二章: NioEventLoop 第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...
- Netty源码分析第2章(NioEventLoop)---->第5节: 优化selector
Netty源码分析第二章: NioEventLoop 第五节: 优化selector 在剖析selector轮询之前, 我们先讲解一下selector的创建过程 回顾之前的小节, 在创建NioEv ...
- Netty源码分析第2章(NioEventLoop)---->第6节: 执行select操作
Netty源码分析第二章: NioEventLoop 第六节: 执行select操作 分析完了selector的创建和优化的过程, 这一小节分析select相关操作 跟到跟到select操作的入口 ...
- Netty源码分析第2章(NioEventLoop)---->第7节: 处理IO事件
Netty源码分析第二章: NioEventLoop 第七节:处理IO事件 上一小节我们了解了执行select()操作的相关逻辑, 这一小节我们继续学习select()之后, 轮询到io事件的相关 ...
- Netty源码分析第2章(NioEventLoop)---->第8节: 执行任务队列
Netty源码分析第二章: NioEventLoop 第八节: 执行任务队列 继续回到NioEventLoop的run()方法: protected void run() { for (;;) ...
- Netty源码分析第4章(pipeline)---->第7节: 前章节内容回顾
Netty源码分析第四章: pipeline 第七节: 前章节内容回顾 我们在第一章和第三章中, 遗留了很多有关事件传输的相关逻辑, 这里带大家一一回顾 首先看两个问题: 1.在客户端接入的时候, N ...
- Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程
Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...
随机推荐
- 4-2 R语言函数 apply
#apply函数,沿着数组的某一维度处理数据 #例如将函数用于矩阵的行或列 #与for/while循环的效率相似,但只用一句话可以完成 #apply(参数):apply(数组,维度,函数/函数名) & ...
- Docker镜像搭建Linux下samba共享目录
Samba 是 SMB/CIFS 网络协议的重新实现, 它作为 NFS 的补充使得在 Linux.OS/2.DOS 和 Windows 系统中进行文件共享.打印机共享更容易实现.SMB协议是客户机/服 ...
- 【转】Android 内核初识(6)SystemServer进程
简介 SystemServer的进程名实际上叫做“system_server”,通常简称为SS. 系统中的服务驻留在其中,常见的比如WindowManagerServer(Wms).ActivityM ...
- Day5 JavaScript(三)事件、表单验证以及初识jQuery
事件 1)鼠标事件 mousedown mouseup 2)键盘事件 a) keydown:键被按下 b) keyup:键抬起 c) keypress:按下可打印字符的键时. document.onk ...
- kendo ui - DatePicker 日期时间系列
kendo-ui 官网:https://www.telerik.com/documentation 初始化 grid: 引入文件: <link rel="stylesheet" ...
- TensorFlow入门:线性回归
随机.mini-batch.batch(见最后解释) 在每个 epoch 送入单个数据点.这被称为随机梯度下降(stochastic gradient descent).我们也可以在每个 epoch ...
- STL容器与拷贝构造函数
所有容器提供的都是“value语意”而非“reference语意”.容器内进行元素的安插操作时,内部实施的是拷贝操作,置于容器内.因此STL容器 的每一个元素都必须能够拷贝.---<<C+ ...
- 【面向对象】用大白话扯扯那"神奇"的面向对象编程思维(二)
前言: 上一章我们用大白话讲解了一下面向对象的编程思维,那么这一张我们来讲讲如何用面向对象来书写代码.终于到了激动人心的时刻了..... 传送门:https://www.cnblogs.com/sy1 ...
- SM30 客户端 有“不可修改”的状态
SM30维护自定义数据表时,遇到提示信息,有“不可修改”的状态,无法修改数据. 查询详细信息,有一条:客户端特定对象不能在此客户端中进行更改. 检查了一下自定表设置,发现自定义表之前创建时,Deliv ...
- 配置bond
注意:配置bond要有两个以上的网口 1.配置文件所有目录:/etc/sysconfig/network-scripts 网口配置文件名规则:以ifcfg-开头,然后接着是网口名 例如:eth0的配置 ...