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. java基础面试题(JVM篇)

    1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程.Java 源文件被编译成能被 Java 虚拟机执行的字节码文件. ...

  2. Odoo的@api.装饰器

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281437.html Odoo自带的api装饰器主要有:model,multi,one,constrains, ...

  3. POJ Football Game 【NIMK博弈 && Bash 博弈】

    Football Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 451   Accepted: 178 Descr ...

  4. Windows7下配置JMeter安装环境

    JMeter配置安装 1.安装JDK环境  下载地址:http://www.Oracle.com/technetwork/Java/javase/downloads/jdk8-downloads-21 ...

  5. 关于lora标配SPDT大功率射频开关

    SPDT大功率的UltraCMOS ™DC - 3.0 GHz射频开关              PE4259的UltraCMOS ™射频开关被设计为覆盖广泛的,通过3000兆赫从近DC应用.这种反射 ...

  6. jenkins -Djava.awt.headless=true Linux下java.awt.HeadlessException的解决办法

    修改 linux  apache-tomcat-7.0.56/bin \catalina.sh文件 在所有类似以下代码大约有七八处具体自己去看:    "$_RUNJAVA" $J ...

  7. cpu负载过高分析

    如何定位是哪个服务进程导致CPU过载,哪个线程导致CPU过载,哪段代码导致CPU过载? 步骤一.找到最耗CPU的进程 工具:top 方法: 执行top -c ,显示进程运行信息列表 键入P (大写p) ...

  8. Java 并发系列(一) ThreadPoolExecutor源码解析及理解

    ThreadPoolExecutor 它是线程池最核心的类, 这里对核心的方法做简要的剖析(会持续更新),以加深对线程池运行原理的理解. 1. 核心成员变量及相关方法 // ctl非常重要,用整型表示 ...

  9. 【js】走近小程序(2) 常见问题总结

    一.API请求? 二.基础库兼容? 三.不同页面之间的传值   一.API请求? wx.request({ url: 'test.php', // 仅为示例,并非真实的接口地址 data: { x: ...

  10. CentOS 7 在最小化安装之后进行安装Apache服务,httpd-2.4.34

    此博文是CentOS 7 在最小化安装之后进行安装Apache服务的操作步骤,httpd版本为httpd-2.4.34. 一.基本服务环境搭建 安装apache需要的基本环境:apr apr-util ...