回顾NIOEVENTLOOP的RUN方法流程

上文说到NioEventLoop的run方法可以分为3个步骤:

  1. 轮询channel中就绪的IO事件
  2. 处理轮询出的IO事件
  3. 处理所有任务,也包括定时任务

其中步骤1已在上一节讲述,这里接着讲述下面2个步骤

IO事件与非IO任务

首先看一下在步骤2和步骤3的主干代码

final int ioRatio = this.ioRatio; // 将所有任务执行完 if (ioRatio == 100) {     try {         processSelectedKeys();     } finally {         // Ensure we always run tasks.         runAllTasks();     } } else {     // 记录IO事件消耗的时间,然后按比例处理分配时间处理非IO任务     final long ioStartTime = System.nanoTime();     try {         processSelectedKeys();     } finally {         // Ensure we always run tasks.         final long ioTime = System.nanoTime() - ioStartTime;         // ioRatio默认50,(100-ioRatio)/ioRatio刚好等于1,做到平均分配         runAllTasks(ioTime * (100 - ioRatio) / ioRatio);     } }

ioRadio是NioEventLoop的一个成员变量,用来控制分配花费在IO事件与非IO任务时间的比例。默认情况下,ioRadio是50,表示IO事件与非IO任务
将分配相同时间。而当ioRatio为100时,该值失效,不再平衡两种动作的时间分配比值。
了解了这一点,上述两种分支代码就不难理解了,我们直接进入processSelectedKeys,看看netty如何执行IO事件

处理IO事件

先进入processSelectedKeys方法内部。

private void processSelectedKeys() {     if (selectedKeys != null) {         processSelectedKeysOptimized();     } else {         processSelectedKeysPlain(selector.selectedKeys());     } }

可以看到这里又根据selectedKeys是否为空这个条件来确定是处理优化过的keys还是普通keys。关于selectedKeys,在NioEventLoop介绍这一节中,
我们介绍了NioEventLoop的创建,在创建过程中,默认会将SelectedKeys由Hashset替换为数组实现,此处的selectedKeys正是替换过后的实现。
我们继续跟进到processSelectedKeysOptimized方法

private void processSelectedKeysOptimized() {     for (int i = 0; i < selectedKeys.size; ++i) {         final SelectionKey k = selectedKeys.keys[i];         selectedKeys.keys[i] = null;         final Object a = k.attachment();         if (a instanceof AbstractNioChannel) {             processSelectedKey(k, (AbstractNioChannel) a);         } else {             NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;             processSelectedKey(k, task);         }         if (needsToSelectAgain) {             selectedKeys.reset(i + 1);             selectAgain();             i = -1;         }     } }

方法内部用一个for循环处理selectedKeys。key的attchment默认是在注册时附加上去的NioServerSocketChannel和NioSocketChannel。
继续跟进processSelectedKey(k, (AbstractNioChannel) a)方法。

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {     final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();     if (!k.isValid()) {         final EventLoop eventLoop = ch.eventLoop();           if (eventLoop != this || eventLoop == null) {             return;         }         unsafe.close(unsafe.voidPromise());         return;     }      int readyOps = k.readyOps();     if ((readyOps & SelectionKey.OP_CONNECT) != 0) {         int ops = k.interestOps();         ops &= ~SelectionKey.OP_CONNECT;         k.interestOps(ops);         unsafe.finishConnect();     }     if ((readyOps & SelectionKey.OP_WRITE) != 0) {         ch.unsafe().forceFlush();     }     if<