概括NIO做了什么不难,讲清楚NIO如何具体实现的,那就有些难度了,原因是NIO实现过程中涉及的参数太多,许多参数看起来不是很重要,但是却在整个流程分析中不可缺少,往往整个过程分析下来还是没办法形成一个清晰的过程。
所以在分析的过程中先不直接从前往后具体分析,而是从宏观到微观分析
接下来将以NIO在Windows平台实现的具体细节展开,以后也会对linux平台进行分析(分析在windows平台的实现不好之处就是不开源,不知道IO多路复用如何实现的),不过也能把NIO的整个过程分析的差不多。
我们都知道NIO中有几个重要角色
Channel、Selector、SelectionKey
我们先来分析Selector的轮询功能实现。

Selector负责轮询,在Windows平台中交给它的子类SubSelector来负责。我们知道IO多路复用的实现有select、poll、epoll等实现方法,windows平台我们不知道具体如何实现,但是总的流程一定是和这些实现方法相仿

return this.poll0(WindowsSelectorImpl.this.pollWrapper.pollArrayAddress, Math.min(WindowsSelectorImpl.this.totalChannels, 1024), this.readFds, this.writeFds, this.exceptFds, WindowsSelectorImpl.this.timeout);
我们可以看到包括几个参数:
我们不进行逐一分析,只需要了解用户空间通过调用poll0的底层方法来实现与内核空间的交互,也就是把这三个数组this.readFds, this.writeFds,this.exceptFds交给内核,内核具体的实现细节我们这里不分析,只需要知道内核会帮我们更新这几个数组来告诉我们哪些感兴趣的事件到来。
poll前
poll后
可以看到通过poll方法让内核帮我们监控感兴趣的事件到来,这时一个感兴趣的事件到来,是个可读事件,它的fdval是1228。
selector的轮询功能的第一步:从内核得到感兴趣事件的到来任务就这样实现了,Selector需要实现的第二步,将这个数据更新到我们的程序上。

通过上面的poll方法我们已经了解,内核会给我们返回三个更新过的数组,分别表示三类事件。

Selector先回对事件进行处理,比较是否是我们感兴趣的事件,然后将SelectionKeysImpl放入Selector专门存放的数据结构

之后就从该数据结构中取出SelectionKeysImpl专门进行处理

用一个去掉一个,直到把set中的全部
