NioEventLoopGroup初始化 (3)

流程图

继续跟进去,上面的NioEventLoopGroup的体系图也就分析到右半部分了,如上图,是这半部分初始化工作的主要流程, 下面是它的构造方法,可以看到主要完成了两件事

进入父类的构造方法完成任务队列的创建

打开选择器,并且进行了优化

细节:
可以看到,现在已经进入了它的三级父类SingleThreadEventExecutor

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) { super(parent); this.addTaskWakesUp = addTaskWakesUp; this.maxPendingTasks = Math.max(16, maxPendingTasks); // todo 保存线程执行器 this.executor = ObjectUtil.checkNotNull(executor, "executor"); // todo 任务队列 , 进入查看 taskQueue = newTaskQueue(this.maxPendingTasks); System.out.println(taskQueue.getClass()); rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler"); }

在这个类中进行了如下的工作:

调用父类的构造方法,设置自己的父Gruop

初始化自己的线程执行器

创建任务队列

队列有啥用?

我们知道,Netty中的线程可不止一个, 多个EventLoop意味着多个线程, 任务队列的作用就是当其他线程拿到CPU的执行权时,却得到了其他线程的IO请求,这时当前线程就把这个请求以任务的方式提交到对应线程的任务队列里面

创建的什么任务队列?

有个误区, 当我跟进newTaskQueue(this.maxPendingTasks);方法时, 进入的方法创建了一个LinkedBlockingQueue队列, 实际上创建的确是MpscQueue , 这并不奇怪,是因为NioEventLoop把这个方法重写了, 源码如下:

@Override protected Queue<Runnable> newTaskQueue(int maxPendingTasks) { // This event loop never calls takeTask() return maxPendingTasks == Integer.MAX_VALUE ? PlatformDependent.<Runnable>newMpscQueue() : PlatformDependent.<Runnable>newMpscQueue(maxPendingTasks); }

这个任务队列的特性是 非阻塞的,多生产者单消费者, 正好和Netty的线程模型对应

此外,这个SingleThreadEventExecutor还有很多重要的方法

excute执行任务

尝试开启线程(初始化EventLoop的线程)

开启线程

执行所有任务

聚合定时任务

把任务丢进队列

把任务从队列中取出

NioEventLoop打开自己的队列时,做了哪些优化?

通过反射,借助Java.Security.AccessController提供的线程安全的策略执行机制把原生JDK的selector的SelectedKeys这个HashSet替换成了数组,使得他的事件复杂度在任何时刻都是O1

// todo 这里进行了 优化, netty把hashSet转换成了数组, 因为在JDK的NIO模型中,获取Selector时, Selector里面内置的存放SelectionKey的容器是Set集合 // todo 而netty把它替换成了自己的数据结构, 数组, 从而使在任何情况下, 它的时间复杂度都是 O1 private SelectorTuple openSelector() { final Selector unwrappedSelector; try { // todo 使用jdk 的api创建新的 selector unwrappedSelector = provider.openSelector(); } catch (IOException e) { throw new ChannelException("failed to open a new selector", e); } if (DISABLE_KEYSET_OPTIMIZATION) { // todo 如果不需要优化,就返回原生的selector , 默认为false 即 使用优化 return new SelectorTuple(unwrappedSelector); } // todo 接下来 netty会用下面这个SelectedSelectionKeySet数据结构 替换原来的 keySet , 进入查看 final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet(); Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { // todo 通过反射 sun.nio.ch.SelectorImpl 或者这个类 return Class.forName( "sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader()); } catch (Throwable cause) { return cause; } } }); // todo 判断是否获取到了这个类 if (!(maybeSelectorImplClass instanceof Class) || // ensure the current selector implementation is what we can instrument. !((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) { if (maybeSelectorImplClass instanceof Throwable) { Throwable t = (Throwable) maybeSelectorImplClass; logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t); } return new SelectorTuple(unwrappedSelector); } // todo 确定是Selector的实现类 换了个名字 final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass; /** * todo 类java.security.AccessController提供了一个默认的安全策略执行机制,它使用栈检查来决定潜在不安全的操作是否被允许。 * todo 这个访问控制器不能被实例化,它不是一个对象,而是集合在单个类中的多个静态方法。 */ Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { // todo 通过反射, 获取到 selectorImplClass的两个字段 selectedKeys publicSelectedKeys // todo selectedKeys publicSelectedKeys底层都是 hashSet() 实现的, 现在获取出来了, 放入上面的数组数据结构中 Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); // todo trySetAccessible 可以强制访问私有的对象 Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField); if (cause != null) { return cause; } // todo trySetAccessible 可以强制访问私有的对象 cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField); if (cause != null) { return cause; } // todo 真正的把通过反射得到的 那两个字段放入我们自己的数据结构中 // // todo 下面是把我们的NioEventLoop中的 unwrappedSelector 的 selectedKeysField的属性 直接设置成 优化后的selectedKeySet selectedKeysField.set(unwrappedSelector, selectedKeySet); publicSelectedKeysField.set(unwrappedSelector, selectedKeySet); return null; } catch (NoSuchFieldException e) { return e; } catch (IllegalAccessException e) { return e; } } }); if (maybeException instanceof Exception) { selectedKeys = null; Exception e = (Exception) maybeException; logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e); return new SelectorTuple(unwrappedSelector); } // todo 初始化自己维护被选中的key的集合 --> 数组类型的 selectedKeys = selectedKeySet; logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector); return new SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet)); }

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

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