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<SelectionKey> 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("selectedKeys");
3Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
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操作