在创建NioEventLoop时会封装一个JDK底层的Selector属性
private Selector selector;
那么我们简单看一下这个Selector在JDK层面的实现
public abstract class SelectorImpl extends AbstractSelector {
protected Set<SelectionKey> selectedKeys = new HashSet();
protected HashSet<SelectionKey> keys = new HashSet();
private Set<SelectionKey> publicKeys;
private Set<SelectionKey> publicSelectedKeys;
protected SelectorImpl(SelectorProvider var1) {
super(var1);
if (Util.atBugLevel("1.4")) {
this.publicKeys = this.keys;
this.publicSelectedKeys = this.selectedKeys;
} else {
this.publicKeys = Collections.unmodifiableSet(this.keys);
this.publicSelectedKeys = Util.ungrowableSet(this.selectedKeys);
}
}
}
从源码中我们可以发现, 当服务器监听到事件后会封装成SelectionKey放到HashSet中, 然后程序就可以从这个HashSet中取出事件进行处理.
而HashSet的add方法的时间复杂度是O(n), 为此Netty通过反射机制, 将底层的这个HashSet用数组替换了, 毕竟向数组中添加数据的时间复杂度是O(1), 那么我们从代码中找到答案吧.
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
selector = openSelector();
}
跟进openSelector()方法
private SelectorTuple openSelector() {
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
}
它创建了一个SelectedSelectionKeySet对象, 我们再看下这个类
final class SelectedSelectionKeySet extends AbstractSet<SelectionKey> {
SelectionKey[] keys;
int size;
SelectedSelectionKeySet() {
keys = new SelectionKey[1024];
}
@Override
public boolean add(SelectionKey o) {
if (o == null) {
return false;
}
keys[size++] = o;
if (size == keys.length) {
increaseCapacity();
}
return true;
}
}
从这里我们可以发现, 这个Set集合底层使用的是数组, 调用add方法时直接向数组中添加元素就可以, 时间复杂度O(1).
接下来看下Netty使用反射替换掉那个HashSet
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
Netty就是通过反射用这个SelectedSelectionKeySet类替换掉了Selector类中的HashSet.
这个地方之所以被Netty搞成这样, 其实还是为了性能. 因为这个地方是涉及数据读写的源头, 如果这个地方的性能不高, 会严重影响到程序的性能. 这也归根结底回到了数据结构的知识.