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

主要是三个步骤:
第一步,取出 IO 事件及对应的 Channel 。其中selectedKeys[i] = null;的目的是防止内存泄漏
第二步,处理 Channel
if (a instanceof AbstractNioChannel) {    processSelectedKey(k, (AbstractNioChannel) a);} else {    @SuppressWarnings("unchecked")    NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;    processSelectedKey(k, task);}Netty 的轮询注册机制其实是将 AbstractNioChannel 内部的 JDK 类 SelectableChannel 对象注册到 JDK 类 Selector 对象上,并且将 AbstractNioChannel 作为SelectableChannel 对象的一个 attachment 附属上,这样在 JDK 轮询出某条 SelectableChannel 有 IO 事件发生时,就可以直接取出 AbstractNioChannel 进行后续操作 。
在Netty的Channel中,有两大类型的Channel,
一个是NioServerSocketChannel,由boss NioEventLoopGroup负责处理;
一个是NioSocketChannel,由worker NioEventLoop负责处理,
所以:
(1)对于boss NioEventLoop来说,轮询到的是连接事件,后续通过NioServerSocketChannel的Pipeline将连接交给一个worker NioEventLoop处理;
(2)对于worker NioEventLoop来说,轮询到的是读写事件,后续通过NioSocketChannel的Pipeline将读取到的数据传递给每个ChannelHandler来处理 。
第三步,判断是否需要再一次轮询
needsToSelectAgain变量控制,needsToSelectAgain变量在如下方法中被调用,在NioEventLoop
private static final int CLEANUP_INTERVAL = 256;    void cancel(SelectionKey key) {        key.cancel();        cancelledKeys ++;        if (cancelledKeys >= CLEANUP_INTERVAL) {            cancelledKeys = 0;            needsToSelectAgain = true;        }    }cancel方法是用于将key取消,并且在被取消的key到达CLEANUP_INTERVAL的时候,设置needsToSelectAgain为 true,CLEANUP_INTERVAL默认值为256 。
也就是说,对于每个NioEventLoop而言,每隔256个Channel从Selector上移除的时候,就标记needsToSelectAgain为true,然后将SelectedKeys的内部数组全部清空,方便JVM垃圾回收,然后调用selectAgain重新填装SelectionKeys数组 。
处理任务队列调用的是如下方法
    protected boolean runAllTasks() {        assert inEventLoop();        boolean fetchedAll;        boolean ranAtLeastOne = false;        do {            fetchedAll = fetchFromScheduledTaskQueue();            if (runAllTasksFrom(taskQueue)) {                ranAtLeastOne = true;            }        } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks.        if (ranAtLeastOne) {            lastExecutionTime = getCurrentTimeNanos();        }        afterRunningAllTasks();        return ranAtLeastOne;    }

经验总结扩展阅读