Netty源码分析第2章(NioEventLoop)—->第5节: 优化selector

释放双眼,带上耳机,听听看~!

 

Netty源码分析第二章: NioEventLoop

** **

第五节: 优化selector

 

在剖析selector轮询之前, 我们先讲解一下selector的创建过程

回顾之前的小节, 在创建NioEventLoop中初始化了唯一绑定的selector:


1
2
3
4
5
6
7
8
9
1NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
2             SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
3    super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
4    //代码省略
5    provider = selectorProvider;
6    selector = openSelector();
7    selectStrategy = strategy;
8}
9

这里 
selector = openSelector() 初始化了selector

我们跟到openSelector()中:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
1private Selector openSelector() {
2    final Selector selector;
3    try {
4        //调用jdk底层的api
5        selector = provider.openSelector();
6    } catch (IOException e) {
7        throw new ChannelException("failed to open a new selector", e);
8    }
9    //判断是否需要关闭优化(默认false, 也就是默认需要优化)
10    if (DISABLE_KEYSET_OPTIMIZATION) {
11        return selector;
12    }
13    //用这个数据结构替换原生的SelectionKeySet
14    final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
15    Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
16        @Override
17        public Object run() {
18            try {
19                //通过反射拿到sun.nio.ch.SelectorImpl这个类的class对象
20                return Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
21            } catch (ClassNotFoundException e) {
22                return e;
23            } catch (SecurityException e) {
24                return e;
25            }
26        }
27    });
28    //判断拿到的是不是class对象并且是不是Selector的实现类
29    if (!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(selector.getClass())) {
30        if (maybeSelectorImplClass instanceof Exception) {
31            Exception e = (Exception) maybeSelectorImplClass;
32            logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
33        }
34        //如果不是他的实现, 就直接返回原生select
35        return selector;
36    }
37    //如果是它的实现, 就拿到其class对象
38    final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
39    Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
40        @Override
41        public Object run() {
42            try {
43                //通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
44                Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
45                Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
46                //设置成可修改的
47                selectedKeysField.setAccessible(true);
48                publicSelectedKeysField.setAccessible(true);
49                //将selector的这两个属性替换成Netty的selectedKeySet
50                selectedKeysField.set(selector, selectedKeySet);
51                publicSelectedKeysField.set(selector, selectedKeySet);
52                return null;
53            } catch (NoSuchFieldException e) {
54                return e;
55            } catch (IllegalAccessException e) {
56                return e;
57            } catch (RuntimeException e) {
58                if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
59                    return e;
60                } else {
61                    throw e;
62                }
63            }
64        }
65    });
66    if (maybeException instanceof Exception) {
67        selectedKeys = null;
68        Exception e = (Exception) maybeException;
69        logger.trace("failed to instrument a special java.util.Set into: {}", selector, e);
70    } else {
71        //将优化后的keySet保存成NioEventLoop的成员变量
72        selectedKeys = selectedKeySet;
73        logger.trace("instrumented a special java.util.Set into: {}", selector);
74    }
75    return selector;
76}
77

这里代码比较长, 我们一点一点的剖析:

首先 
selector = provider.openSelector() 这里创建了jdk底层的selector


1
2
3
4
1if (DISABLE_KEYSET_OPTIMIZATION) {
2    return selector;
3}
4

这里判断了是否关闭优化功能, 默认是false, 也就是需要优化, 这里的意思就是netty需要对jdk原生的selector进行了优化, 我们知道selector在select()操作时候, 会通过selector.selectedKeys()操作返回一个Set<SelectionKey>, 这个是Set类型, netty对这个set进行了处理, 使用SelectedSelectionKeySet的数据结构进行替换, 当在select()操作时将key存入一个SelectedSelectionKeySet的数据结构中

 


1
2
1final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
2

这里一步创建了这个优化后的数据结构

简单跟一下SelectedSelectctionKeySet这个类的构造方法:


1
2
3
4
5
1SelectedSelectionKeySet() {
2    keysA = new SelectionKey[1024];
3    keysB = keysA.clone();
4}
5

初始化了两个属性keysA和keysB, 说明这类其实底层是通过数组实现的, 通过操作数组下标会有更高的效率

这个类的的flip()方法, 则返SelectionKey[]数组


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1SelectionKey[] flip() {
2    if (isA) {
3        isA = false;
4        keysA[keysASize] = null;
5        keysBSize = 0;
6        return keysA;
7    } else {
8        isA = true;
9        keysB[keysBSize] = null;
10        keysASize = 0;
11        return keysB;
12    }
13}
14

再看下其他方法:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1@Override
2public boolean remove(Object o) {
3    return false;
4}
5
6@Override
7public boolean contains(Object o) {
8    return false;
9}
10@Override
11public Iterator&lt;SelectionKey&gt; iterator() {
12    throw new UnsupportedOperationException();
13}
14

我们看到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对象

然后就做了真正的替换操作:


1
2
3
4
5
6
7
8
9
10
1//通过反射拿到selectedKeys和publicSelectedKeys两个属性, 默认这两个属性底层都是hashSet方式实现的
2Field selectedKeysField = selectorImplClass.getDeclaredField(&quot;selectedKeys&quot;);
3Field publicSelectedKeysField = selectorImplClass.getDeclaredField(&quot;publicSelectedKeys&quot;);
4//设置成可修改的
5selectedKeysField.setAccessible(true);
6publicSelectedKeysField.setAccessible(true);
7//将selector的这两个属性替换成Netty的selectedKeySet
8selectedKeysField.set(selector, selectedKeySet);
9publicSelectedKeysField.set(selector, selectedKeySet);
10

通过注释我们不难看出, 这里将新创建selectedKeySet替换了selector对象中的selectedKeysField, 和selectedKeysField两个属性

最后通过 
selectedKeys = selectedKeySet 将优化的数据结构selectedKeySet保存在NioEventLoop的成员变量中

最后返回优化后的selector

这样, selector在select()操作的过程中, 如果有就绪事件则会将返回的key存放在selectedKeySet所对应的数组中

 

上一节: NioEventLoop线程启动

下一节: 执行select操作

 

给TA打赏
共{{data.count}}人
人已打赏
安全技术

node.js – JWT有效负载应该有多少信息?

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索