什么是 NIO
同步/异步 阻塞/非阻塞
Unix I/O 模型:
输入操作分为两个阶段:等待数据准备好,从内核向进程复制数据
同步:阻塞式(调用未完成,进程挂起),非阻塞式(调用完成,返回失败结
果),I/O 多路复用(阻塞 select,不阻塞 I/O 调用,进程阻塞于 select 调
用,等待任一套接口变为可用,系统调用进行数据读取),信号驱动式 I/O
(sigio,内核通过信号告知数据准备好)
异步 I/O(内核告诉你 I/O 完成)
从不同层面看:
CPU 层面:操作系统对于 cpu 调度和 io 操作一般是异步非阻塞的方式。CPU 发
出 io 请求后不再等待 io 操作(数据放入磁盘控制器缓冲区),而是继续执行
其他任务(非阻塞),DMA 负责将数据读取到内核缓冲区,然后发送通知给
CPU,这个过程 io 操作和 cpu 异步进行。
线程层面:操作系统为了应用层面的开发简单(程序运行结果和编程顺序相
同),将底层的异步非阻塞封装为了同步阻塞(read,write 方法等系统调用
时,os 会阻塞进程,让出 cpu 资源)。如果直接使用阻塞方法,会使线程挂
起,如果使用非阻塞方式(轮询),都会使 cpu 资源浪费。解决办法:
1.多线程(同步阻塞)
2.IO 多路复用(select,poll,epoll)(同步非阻塞,系统调用不再阻塞,
线程阻塞于 select 函数)
3.异步 IO 接口,kernel-aio,IOCP
感知层次:对 IO 多路复用进行进一步封装(异步 nio,netty 等)
事件驱动 reactor
一.成员
1.handle:由操作系统管理的资源。包括网络连接,打开的文件,计时器,同
步对象等。
2.Synchronous Event Demultiplexer(同步事件分离器): 本身是一个系统调
用,用于等待一组时间的发生。调用者会在这里阻塞,直到可以非阻塞的完成
对 handle 的操作。也就是 I/O 多路复用,对于 linux 是 select,epoll,对于
java NIO 就是 selector。
3.Initiation Dispatcher(初始分发器):Reactor 角色。定义了用于注册,删
除和分派 event handlers 的接口。同步事件分离器负责等待新事件的发生,当
它检测到新事件时,会通知初始分发器调用特定的应用程序的事件处理器。常
见事件包括接受连接,数据 io 和超时事件。
4.Event Handler(事件处理器):由钩子方法组成的接口,该方法抽象的表示
特定应用的某个服务的事件的调度操作。(java nio 中没有实际的对应组件)
(Netty 中就有很多对应组件,ChannelInboundHandlerAdapter)