Netty源码—一、server启动(1) (3)

可以看出上面两个chooser计算出的最终结果是一致的,但是使用位运算更快一点,所以如果是线程池的大小刚好是2的幂次的话使用位运算的chooser。

args // args[0],下面方法返回的provider,在linux平台上默认是EPollSelectorProvider java.nio.channels.spi.SelectorProvider#provider // args[1],决定eventLoop每次执行select还是执行队列中的任务 io.netty.channel.DefaultSelectStrategyFactory // args[2],等待队列满以后的拒绝策略 io.netty.util.concurrent.RejectedExecutionHandlers#REJECT

初始化NioEventLoopGroup过程主要是为了初始化线程池中每一个NioEventLoop,而每一个NioEventLoop包含一个selector。

初始化selector

接着上面说到的初始化NioEventLoop,调用newChild方法来初始化

// io.netty.channel.nio.NioEventLoopGroup#newChild protected EventLoop newChild(Executor executor, Object... args) throws Exception { // 下面这几个参数上面已经介绍过 return new NioEventLoop(this, executor, (SelectorProvider) args[0], ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]); } NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) { // 调用父类构造方法初始化taskQueue,taskQueue的大小取Math.max(16, maxPendingTasks) super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler); // 校验selectorProvider if (selectorProvider == null) { throw new NullPointerException("selectorProvider"); } // 校验EventLoop每次执行的select策略是否为空 if (strategy == null) { throw new NullPointerException("selectStrategy"); } provider = selectorProvider; // 初始化selector selector = openSelector(); selectStrategy = strategy; } private Selector openSelector() { final Selector selector; try { // 调用的是sun.nio.ch.EPollSelectorProvider#openSelector // 返回的是sun.nio.ch.EPollSelectorImpl selector = provider.openSelector(); } catch (IOException e) { throw new ChannelException("failed to open a new selector", e); } // 是否使用SelectedSelectionKeySet优化,默认不禁用false if (DISABLE_KEYSET_OPTIMIZATION) { return selector; } // Netty优化过后的 final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet(); // 尝试获取SelectorImpl对象,后续会使用反射操作这个类的属性 Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { return Class.forName( "sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader()); } catch (ClassNotFoundException e) { return e; } catch (SecurityException e) { return e; } } }); // 确保有权限访问该类 if (!(maybeSelectorImplClass instanceof Class) || // ensure the current selector implementation is what we can instrument. !((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); } return selector; } final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass; Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { // 得到字段selectedKeys Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); // 得到字段publicSelectedKeys Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); selectedKeysField.setAccessible(true); publicSelectedKeysField.setAccessible(true); // 将selectedKeys、publicSelectedKeys均设置为Netty自定义的SelectedSelectionKeySet selectedKeysField.set(selector, selectedKeySet); publicSelectedKeysField.set(selector, selectedKeySet); return null; } catch (NoSuchFieldException e) { return e; } catch (IllegalAccessException e) { return e; } catch (RuntimeException e) { // JDK 9 can throw an inaccessible object exception here; since Netty compiles // against JDK 7 and this exception was only added in JDK 9, we have to weakly // check the type 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 { selectedKeys = selectedKeySet; logger.trace("instrumented a special java.util.Set into: {}", selector); } return selector; }

初始化selector的过程中主要做了几件事:

使用平台相关的provider初始化对应的SelectorImpl,这里使用了Java的SPI来加载平台相关的provider,每一种provider又对应一种SelectorImpl

如果没有禁用selectedKey优化,Netty会使用自定的SelectedSelectionKeySet替换SelectorImpl的publicSelectedKeys、selectedKeys

对SelectorImpl.selectedKey优化的说明

利用反射将SelectorImpl.selectedKey替换成了SelectedSelectionKeySet,SelectedSelectionKeySet利用数组实现元素存放

在调用select方法的时候如果有事件进来的时候会调用SelectedSelectionKeySet#add,将有IO事件的selectKey添加到keyset中

使用数组遍历(processSelectedKeysOptimized)要比使用set遍历快一些,参考文后第一篇参考文章

在Java9以后这个优化就失效了,因为Java9引入了Jigsaw

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsffps.html