Netty源码分析第2章(NioEventLoop)---->第5节: 优化selector
Netty源码分析第二章: NioEventLoop
第五节: 优化selector
在剖析selector轮询之前, 我们先讲解一下selector的创建过程
回顾之前的小节, 在创建NioEventLoop中初始化了唯一绑定的selector:
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
//代码省略
provider = selectorProvider;
selector = openSelector();
selectStrategy = strategy;
}
这里 selector = openSelector() 初始化了selector
我们跟到openSelector()中:
private Selector openSelector() {
final Selector selector;
try {
//调用jdk底层的api
selector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
//判断是否需要关闭优化(默认false, 也就是默认需要优化)
if (DISABLE_KEYSET_OPTIMIZATION) {
return selector;
}
//用这个数据结构替换原生的SelectionKeySet
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
//通过反射拿到sun.nio.ch.SelectorImpl这个类的class对象
return Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
} catch (ClassNotFoundException e) {
return e;
} catch (SecurityException e) {
return e;
}
}
});
//判断拿到的是不是class对象并且是不是Selector的实现类
if (!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass())) {
if (maybeSelectorImplClass instanceof Exception) {
Exception e = (Exception) maybeSelectorImplClass;
logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
}
//如果不是他的实现, 就直接返回原生select
return selector;
}
//如果是它的实现, 就拿到其class对象
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
//通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
//设置成可修改的
selectedKeysField.setAccessible(true);
publicSelectedKeysField.setAccessible(true);
//将selector的这两个属性替换成Netty的selectedKeySet
selectedKeysField.set(selector, selectedKeySet);
publicSelectedKeysField.set(selector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
} catch (RuntimeException e) {
if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
return e;
} else {
throw e;
}
}
}
});
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
} else {
//将优化后的keySet保存成NioEventLoop的成员变量
selectedKeys = selectedKeySet;
logger.trace("instrumented a special java.util.Set into: {}", selector);
}
return selector;
}
这里代码比较长, 我们一点一点的剖析:
首先 selector = provider.openSelector() 这里创建了jdk底层的selector
if (DISABLE_KEYSET_OPTIMIZATION) {
return selector;
}
这里判断了是否关闭优化功能, 默认是false, 也就是需要优化, 这里的意思就是netty需要对jdk原生的selector进行了优化, 我们知道selector在select()操作时候, 会通过selector.selectedKeys()操作返回一个Set<SelectionKey>, 这个是Set类型, netty对这个set进行了处理, 使用SelectedSelectionKeySet的数据结构进行替换, 当在select()操作时将key存入一个SelectedSelectionKeySet的数据结构中
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
这里一步创建了这个优化后的数据结构
简单跟一下SelectedSelectctionKeySet这个类的构造方法:
SelectedSelectionKeySet() {
keysA = new SelectionKey[1024];
keysB = keysA.clone();
}
初始化了两个属性keysA和keysB, 说明这类其实底层是通过数组实现的, 通过操作数组下标会有更高的效率
这个类的的flip()方法, 则返SelectionKey[]数组
SelectionKey[] flip() {
if (isA) {
isA = false;
keysA[keysASize] = null;
keysBSize = 0;
return keysA;
} else {
isA = true;
keysB[keysBSize] = null;
keysASize = 0;
return keysB;
}
}
再看下其他方法:
@Override
public boolean remove(Object o) {
return false;
} @Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<SelectionKey> iterator() {
throw new UnsupportedOperationException();
}
我们看到remove()方法, contains()方法都返回了false, 说明其不支持删除方法和包含方法, iterator()方法则直接抛出异常, 说明其不支持迭代器操作
回到openSelector()中:
再往下看, 这里通过 Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader()) 创建了一个SelectorImpl的class对象
if(!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass()))
这里判断拿到的对象是否为class对象并且是否为Selector的实现类, 如果不是, 则直接返回jdk的selector
如果是, 就继续转化成class对象
然后就做了真正的替换操作:
//通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
//设置成可修改的
selectedKeysField.setAccessible(true);
publicSelectedKeysField.setAccessible(true);
//将selector的这两个属性替换成Netty的selectedKeySet
selectedKeysField.set(selector, selectedKeySet);
publicSelectedKeysField.set(selector, selectedKeySet);
通过注释我们不难看出, 这里将新创建selectedKeySet替换了selector对象中的selectedKeysField, 和selectedKeysField两个属性
最后通过 selectedKeys = selectedKeySet 将优化的数据结构selectedKeySet保存在NioEventLoop的成员变量中
最后返回优化后的selector
这样, selector在select()操作的过程中, 如果有就绪事件则会将返回的key存放在selectedKeySet所对应的数组中
Netty源码分析第2章(NioEventLoop)---->第5节: 优化selector的更多相关文章
- Netty源码分析第2章(NioEventLoop)---->第1节: NioEventLoopGroup之创建线程执行器
Netty源码分析第二章: NioEventLoop 概述: 通过上一章的学习, 我们了解了Server启动的大致流程, 有很多组件与模块并没有细讲, 从这个章开始, 我们开始详细剖析netty的各个 ...
- Netty源码分析第2章(NioEventLoop)---->第2节: NioEventLoopGroup之NioEventLoop的创建
Netty源码分析第二章: NioEventLoop 第二节: NioEventLoopGroup之NioEventLoop的创建 回到上一小节的MultithreadEventExecutorG ...
- Netty源码分析第2章(NioEventLoop)---->第3节: 初始化线程选择器
Netty源码分析第二章:NioEventLoop 第三节:初始化线程选择器 回到上一小节的MultithreadEventExecutorGroup类的构造方法: protected Multi ...
- Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动
Netty源码分析第二章: NioEventLoop 第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...
- 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读取数据的流程: 首先 ...
随机推荐
- 20155314 2016-2017-2 《Java程序设计》第4周学习总结
20155314 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 理解封装.继承.多态的关系 理解抽象类与接口的区别 掌握S.O.L.I.D原则 了解模式和设 ...
- Python读文件报错:SyntaxError: Non-ASCII character in file
打开city.py文件时报错 问题原因: 程序中的编码错误,python默认是acii模式,没有支持utf8.如果代码中有汉字 ,就会报错 解决方案: 源代码文件(city.py)第一行添加:#cod ...
- python开发_stat
当我们使用os.stat(path)获取一个文件(夹)信息的时候, os.stat(path)本身返回的是一个元组如: nt.stat_result(st_mode=33206, st_ino=203 ...
- java 输出流 outputstream
一:输入和输出概念 输入流(inputstream):对于java程序来说,从程序写入文件叫做输出. 输出流(outputstream):对于java程序来说,从文件读取数据,到java程序叫做输入. ...
- 2018年秋季学期《C语言程序设计I》教学过程及学期总结
一学期下来,问题很多,思考也很多,需要整理.总结,好的经验要形成规律,不好的地方要提示警醒. 教学过程小结: C语言程序设计I-第一周教学 C语言程序设计I-第三周教学 C语言程序设计I-第四周教学 ...
- CanOpen协议【CanFestival】移植方法 支持VC、QT、STM32
前段时间学习了CanOpen协议,到网上下载的CanFestival3-10源码,移植到VC.QT.STM32等平台,由于网上的资源较少,走了不少弯路,移植好使用过程中才逐渐暴露出各种问题,比如OD字 ...
- 不大于N的所有素数
算法如下: #include<stdio.h> #include<math.h> void Sieve(int n) { int p,j,i; ],L[n+]; ;p<= ...
- oracle 判断字段相等,但类型不同引起的性能问题
最近做ogg数据同步,然后触发器加工数据放入另外一张表,由于数据量很大,一分钟几万条数据,由于一些条件字段类型不匹配,引起ogg阻塞,比较头大.最后分析发现性能问题.请看下图: phmxxh是varc ...
- mysql/mariadb学习记录——查询2
Alias——使用一个列名别名AS 关键字: mysql> select sno as studentId,sname as studentName from student; +------- ...
- ETL项目2:大数据清洗,处理:使用MapReduce进行离线数据分析并报表显示完整项目
ETL项目2:大数据清洗,处理:使用MapReduce进行离线数据分析并报表显示完整项目 思路同我之前的博客的思路 https://www.cnblogs.com/symkmk123/p/101974 ...