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所对应的数组中

上一节: NioEventLoop线程启动

下一节: 执行select操作

Netty源码分析第2章(NioEventLoop)---->第5节: 优化selector的更多相关文章

  1. Netty源码分析第2章(NioEventLoop)---->第1节: NioEventLoopGroup之创建线程执行器

    Netty源码分析第二章: NioEventLoop 概述: 通过上一章的学习, 我们了解了Server启动的大致流程, 有很多组件与模块并没有细讲, 从这个章开始, 我们开始详细剖析netty的各个 ...

  2. Netty源码分析第2章(NioEventLoop)---->第2节: NioEventLoopGroup之NioEventLoop的创建

    Netty源码分析第二章: NioEventLoop   第二节: NioEventLoopGroup之NioEventLoop的创建 回到上一小节的MultithreadEventExecutorG ...

  3. Netty源码分析第2章(NioEventLoop)---->第3节: 初始化线程选择器

    Netty源码分析第二章:NioEventLoop   第三节:初始化线程选择器 回到上一小节的MultithreadEventExecutorGroup类的构造方法: protected Multi ...

  4. Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动

    Netty源码分析第二章: NioEventLoop   第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...

  5. Netty源码分析第2章(NioEventLoop)---->第6节: 执行select操作

    Netty源码分析第二章: NioEventLoop   第六节: 执行select操作 分析完了selector的创建和优化的过程, 这一小节分析select相关操作 跟到跟到select操作的入口 ...

  6. Netty源码分析第2章(NioEventLoop)---->第7节: 处理IO事件

    Netty源码分析第二章: NioEventLoop   第七节:处理IO事件 上一小节我们了解了执行select()操作的相关逻辑, 这一小节我们继续学习select()之后, 轮询到io事件的相关 ...

  7. Netty源码分析第2章(NioEventLoop)---->第8节: 执行任务队列

      Netty源码分析第二章: NioEventLoop   第八节: 执行任务队列 继续回到NioEventLoop的run()方法: protected void run() { for (;;) ...

  8. Netty源码分析第4章(pipeline)---->第7节: 前章节内容回顾

    Netty源码分析第四章: pipeline 第七节: 前章节内容回顾 我们在第一章和第三章中, 遗留了很多有关事件传输的相关逻辑, 这里带大家一一回顾 首先看两个问题: 1.在客户端接入的时候, N ...

  9. Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程

    Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...

随机推荐

  1. 1927. [SDOI2010]星际竞速【费用流】

    Description 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的 梦想,来自杰森座α星的悠悠也是其中之一.赛车大赛的赛场由N颗行星和M条双向星 ...

  2. Linux - 版本控制系统SVN

    0. 摘要 本文通过搭建SVN多版本库为例,介绍SVN的使用. SVN是一个集中式版本控制系统,在服务端部署中央版本库,所有开发人员客户端连接到中央版本库进行代码的提交和更新. Apache Subv ...

  3. C# winform webbrowser如何指定内核为IE11?

    1)假设你应用程序的名字为MyApplication.exe 2)运行Regedit,打开注册表,找到 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsof ...

  4. eclipse中文乱码解决

    1. 改变整个文件类型的编码格式 1)  eclipse->window->preferences->General->Content Types    2)  找到要修改的文 ...

  5. 多线程之Timer和TimerTask

    Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask.TimerTask是一个抽象类,实现了Runnabl ...

  6. Maven/Ant的安装(Win10 x64)

    一.Maven安装 1.官网下载安装包,http://maven.apache.org/download.cgi. 2.安装包解压到某一目录,然后配置maven的环境变量. PS:也可以不配置环境变量 ...

  7. [Phonegap+Sencha Touch] 移动开发29 安卓navigator.camera.getPicture得到图片的真实路径

    原文地址:http://blog.csdn.net/lovelyelfpop/article/details/38313021 phonegap的拍照插件选择图库中的图片.代码例如以下: naviga ...

  8. java核心技术-多线程之线程基础

    说起线程,无法免俗首先要弄清楚的三个概念就是:进程.线程.协程.OK,那什么是进程,什么是线程,哪协程又是啥东西.进程:进程可以简单的理解为运行在操作系统中的程序,程序时静态代码,进程是动态运行着的代 ...

  9. Mac编译安装swfTools

    Mac编译安装swfTools Mac编译安装swfTools 下载源码 解压源码 安装依赖项 ./configure执行配置或者执行如下配置命令: 需要注意这里存在部分代码错误,需要修改解决后执行 ...

  10. nginx如何做到TCP的负载均衡

    原文:https://blog.csdn.net/u011218159/article/details/50966861   TCP 的 负载均衡   这个片段描述了如何通过nginx plus进行负 ...