Queue<Runnable> newTaskQueue(int maxCapacity);这个Queue必须是线程安全的,并且继承自
java.util.concurrent.BlockingQueue.
讲解完这几个参数,接下来我们就可以详细查看NioEventLoop的具体NIO实现了 。
NioEventLoop首先NioEventLoop和DefaultEventLoop一样,都是继承自SingleThreadEventLoop:
public final class NioEventLoop extends SingleThreadEventLoop表示的是使用单一线程来执行任务的EventLoop 。
首先作为一个NIO的实现,必须要有selector,在NioEventLoop中定义了两个selector,分别是selector和unwrAppedSelector:
private Selector selector;private Selector unwrappedSelector;在NioEventLoop的构造函数中,他们是这样定义的:
final SelectorTuple selectorTuple = openSelector();this.selector = selectorTuple.selector;this.unwrappedSelector = selectorTuple.unwrappedSelector;首先调用openSelector方法,然后通过返回的SelectorTuple来获取对应的selector和unwrappedSelector 。
这两个selector有什么区别呢?
在openSelector方法中,首先通过调用provider的openSelector方法返回一个Selector,这个Selector就是unwrappedSelector:
final Selector unwrappedSelector;unwrappedSelector = provider.openSelector();然后检查
DISABLE_KEY_SET_OPTIMIZATION是否设置,如果没有设置那么unwrappedSelector和selector实际上是同一个Selector:
DISABLE_KEY_SET_OPTIMIZATION表示的是是否对select key set进行优化:
if (DISABLE_KEY_SET_OPTIMIZATION) {return new SelectorTuple(unwrappedSelector);}SelectorTuple(Selector unwrappedSelector) {this.unwrappedSelector = unwrappedSelector;this.selector = unwrappedSelector;}如果
DISABLE_KEY_SET_OPTIMIZATION被设置为false,那么意味着我们需要对select key set进行优化,具体是怎么进行优化的呢?
先来看下最后的返回:
return new SelectorTuple(unwrappedSelector,new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));最后返回的SelectorTuple第二个参数就是selector,这里的selector是一个
SelectedSelectionKeySetSelector对象 。
SelectedSelectionKeySetSelector继承自selector,构造函数传入的第一个参数是一个delegate,所有的Selector中定义的方法都是通过调用delegate来实现的,不同的是对于select方法来说,会首先调用selectedKeySet的reset方法,下面是以isOpen和select方法为例观察一下代码的实现:
public boolean isOpen() {return delegate.isOpen();}public int select(long timeout) throws IOException {selectionKeys.reset();return delegate.select(timeout);}selectedKeySet是一个SelectedSelectionKeySet对象,是一个set集合,用来存储SelectionKey,在openSelector()方法中,使用new来实例化这个对象:
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();netty实际是想用这个SelectedSelectionKeySet类来管理Selector中的selectedKeys,所以接下来netty用了一个高技巧性的对象替换操作 。
首先判断系统中有没有sun.nio.ch.SelectorImpl的实现:
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {try {return Class.forName("sun.nio.ch.SelectorImpl",false,PlatformDependent.getSystemClassLoader());} catch (Throwable cause) {return cause;}}});SelectorImpl中有两个Set字段:
private Set<SelectionKey> publicKeys;private Set<SelectionKey> publicSelectedKeys;这两个字段就是我们需要替换的对象 。如果有SelectorImpl的话,首先使用Unsafe类,调用PlatformDependent中的objectFieldOffset方法拿到这两个字段相对于对象示例的偏移量,然后调用putObject将这两个字段替换成为前面初始化的selectedKeySet对象:
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {// Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.// This allows us to also do this in Java9+ without any extra flags.long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);long publicSelectedKeysFieldOffset =PlatformDependent.objectFieldOffset(publicSelectedKeysField);if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {PlatformDependent.putObject(unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);PlatformDependent.putObject(unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);return null;}如果系统设置不支持Unsafe,那么就用反射再做一次:
推荐阅读
- 红茶是怎么制作的?
- 手把手教你进行安卓逆向之篡改apk名称和图标
- 资生堂男士洗面奶五诺系列介绍
- “永恒之蓝”勒索病毒实战演练
- 一文了解MQTT协议
- 哪些瑜伽动作瘦肚子
- 五岳之首的泰山在哪里
- 程序员之间神奇的鄙视链,你在其中哪一层?
- Linux内核内存分配函数之kmalloc
- 阳台养花风水之养花忌讳
