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详解