七 Netty 学习:NioEventLoop 对应线程的创建和启动源码说明( 四 )

处理 IO 事件的 Channel调用的是NioEventLoop的如下方法
    private void processSelectedKeys() {        if (selectedKeys != null) {            // 处理优化过的 SelectedKeys            processSelectedKeysOptimized();        } else {            // 处理正常的 SelectedKeys            processSelectedKeysPlain(selector.selectedKeys());        }    }上述两个分支分别处理了不同类型的 key:重点关注优化过的 SelectedKeys,selectedKeys 在 NioEventLoop 中是一个SelectedSelectionKeySet对象,这个对象虽然叫Set,但是底层使用了数组
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;    }    ......}add 方法的主要流程是:

  1. 将SelectionKey塞到该数组的尾部;
  2. 更新该数组的逻辑长度+1;
  3. 如果该数组的逻辑长度等于数组的物理长度,就将该数组扩容 。
待程序运行一段时间后,等数组的长度足够长,每次在轮询到 NIO 事件的时候,Netty 只需要O(1)的时间复杂度就能将SelectionKey塞到set中去,而 JDK 底层使用的HashSet,put的时间复杂度最少是O(1),最差是O(n) 。
进入processSelectedKeysOptimized方法
    private void processSelectedKeysOptimized(SelectionKey[] selectedKeys) {        for (int i = 0;; i ++) {            final SelectionKey k = selectedKeys[i];            if (k == null) {                break;            }            // null out entry in the array to allow to have it GC'ed once the Channel close            // See https://github.com/netty/netty/issues/2363            selectedKeys[i] = null;            final Object a = k.attachment();            if (a instanceof AbstractNioChannel) {                processSelectedKey(k, (AbstractNioChannel) a);            } else {                @SuppressWarnings("unchecked")                NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;                processSelectedKey(k, task);            }            if (needsToSelectAgain) {                // null out entries in the array to allow to have it GC'ed once the Channel close                // See https://github.com/netty/netty/issues/2363                for (;;) {                    i++;                    if (selectedKeys[i] == null) {                        break;                    }                    selectedKeys[i] = null;                }                selectAgain();                // Need to flip the optimized selectedKeys to get the right reference to the array                // and reset the index to -1 which will then set to 0 on the for loop                // to start over again.                //                // See https://github.com/netty/netty/issues/1523                selectedKeys = this.selectedKeys.flip();                i = -1;            }        }    }

经验总结扩展阅读