Nio基于 Reactor(反应器)模式。
需要先了解Reactor!
Liunx 对Reactor IO 设计的支持是Epoll
EPollArrayWrapper的核心要点如下:
1: EPollArrayWrapper 是JAVA 对Epoll的封装(不是重新实现)
2: "真正" select() 是 EPollArrayWrapper实现的(也就是Nio中的IO感知)
3: EPollArrayWrapper 在封装Epoll 同时支持了JAVA的中断机制
这里我们需要先理解Linux Epoll是什么个功能 是怎么设计的(一切皆文件,这个概念很重要)
如果还不了解的: www.cnblogs.com/DarkH/archi...
epoll_event是事件(为了屏蔽C与JAVA的不同 统一称为enent) epoll_data 如果熟悉lambda的同学就可以把它想象成callback epoll 是不会解它的,怎么进来的就怎么回去
上述需要着重关注的属性如果下:
outgoingInterruptFD
incomingInterruptFD
interruptedIndex
这三个字段是NIO 中断支持的关键字段
Nio是怎么设计支持的呢
答案是: 模拟IO行为 使用特殊的管道
Nio 会创建了一个无名管道,并返回一个长整数(long),该整数实际上编码了两个文件描述符。 无名管道在UNIX和Linux系统中是一个很基本的IPC(进程间通信)机制,它提供了两个文件描述符:一个用于读,另一个用于写。 fd0通常是读端。 fd1通常是写端。
Reactor模式只有一条BOSS线程负责和Epoll交互 它也只干这件事。 那么Epoll阻塞的线程 也只会是它 当这条Boss总线感到IO事件发生了(Epoll通知的), 它会检查是否中断管道发生的 如果是 那么Boss线程就知道要中断自己了!
outgoingInterruptFD就是外部写信息的端口。 incomingInterruptFD就是内部检查(EPollArrayWrapper )的端口.interruptedIndex只是确定事件位置。
updated 已经就绪的IO数量
updateCount 已经注册需要改变fd的数量(fd) 这里改变不是fd 而是fd关心的事件
updateDescriptors 装fd的数组(因为fd是一个int 那么add和find 都是O(n))
eventsLow 这里需要着重理解下 fd是个int 那么eventsLow[A] 那么就是A fd,而 value是此fd感兴趣的event
上述这些都是基础方法 是操作fd和 对应event的存取的
注意理解 (b== mask) 这里考虑了位比较的情况 也就是说虽然 mask入参类型是int 都希望它是byte。那问题又来了 为什么不直接使用byte 因为java byte是有符号的 无法区分-1 和 255
核心方法:
处理已注册的fd更新申请。 一定要理解 预存 也就是处理时机 不是你注册申请Nio 就会马上给你处理 它是必须等待下一轮epollwait的结束后一次性处理!!
Poll()是配合Reactor模式设计的 只有BOSS线程调用poll 也只需要只干这件事
ini
if (getDescriptor(i) == incomingInterruptFD) {
interruptedIndex = i;
interrupted = true;
break;
}
检查此次IO事情是否为中断线程如果是就打上interrupted!
我们最后看看JNI_C的实现