Selector事件分发器(单线程选择就绪的事件)作为Java NIO的核心组件,这里详细了解内部实现
服务端代码
| 
 | 
 | 
- 如果有客户端A连接服务,执行select方法时,可以通过serverSocketChannel获取客户端A的socketChannel,并在selector上注册socketChannel的OP_READ事件。
- 如果客户端A发送数据,会触发OP_READ事件,这样下次轮询调用select方法时,就能通过socketChannel读取数据,同时在selector上注册该socketChannel的OP_WRITE事件,实现服务器往客户端写数据。
Selector.open()实现原理
注意:以下源代码皆来源于openjdk8
- Selector.open()可以得到一个- Selector实例
| 
 | 
 | 
- sun.nio.ch.DefaultSelectorProvider
不同系统对应着不同的sun.nio.ch.DefaultSelectorProvider,以Linux为例:
| 
 | 
 | 
如果系统名称是Linux的话,真正创建的是sun.nio.ch.EPollSelectorProvider
| 
 | 
 | 
Linux最终的Selector实现:sun.nio.ch.EPollSelectorImpl
EPollSelectorImpl.select()实现原理
epoll系统调用主要分为3个函数: epoll_create, epoll_ctl, epoll_wait
epoll_create:创建一个epoll fd
| 
 | 
 | 
 创建一个EPollArrayWrapper 初始化
| 
 | 
 | 
在初始化过程中调用了native epollCreate方法。
| 
 | 
 | 
epoll_create: 内核系统调用,创建一个epoll fd, 并且开辟epoll自己的内核高速cache区,建立红黑树分配初始size的内存对象,同时建立一个list链表,用于存储准备就绪的事件
Epoll wait:等待内核IO事件
调用Selector.select(),最后会委托给EPollSelectorImpl的doSelect()方法
| 
 | 
 | 
实际执行EPollArrayWrapper.poll(timeout);
| 
 | 
 | 
epollWait也是个native方法:
| 
 | 
 | 
epoll_wait: 内核系统调用, 等待内核返回IO事件
epoll_ctl: IO事件管理
注册到Selector上的IO事件是使用SelectionKey来表示,代表了Channel感兴趣的事件,如Read,Write,Connect,Accept.
调用Selector.register()完成IO事件注册,实际执行EPollSelectorImpl.implRegister()方法
| 
 | 
 | 
调用Selector.register()时均会将事件存储到EpollArrayWrapper的成员变量eventsLow和eventsHigh中
| 
 | 
 | 
执行EpollArrayWrapper.poll()的时候, 首先会调用updateRegistrations()
| 
 | 
 | 
在获取到事件之后将操作委托给了epollCtl,这又是个native方法:
| 
 | 
 | 
注意:jdk nio没有指定ET(边缘触发)还是LT(水平触发), 所以默认会用LT, 而Netty epoll transport使用ET触发

通过channel就能不断的获取客户端socket数据,实现后端业务处理
参考
Java NIO分析(8): 高并发核心Selector详解