常见I/O模型及Java I/O
常见I/O模型及Java I/O
分类方式(拿网上的餐馆点菜来理解)
阻塞和非阻塞:
描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。
- 阻塞:到饭店吃饭,一直等直到菜好了,否则不能干其他事情。例子:data = socket.read()
- 非阻塞:到饭店吃饭,点了菜之后可以去干其他事情。
同步和异步:
描述的是用户线程与内核的交互方式:同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;而异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数,收到内核返回的成功或失败信号后说明I/O操作及结果并直接使用数据。
- 同步:到饭店点餐,点完了之后要自己隔一段时间问厨师才做好了没,不然啥也不知道。
- 异步:到饭店点餐,点完了之后,有人通知你菜做好了可以吃了。
几种常见的I/O模型
阻塞I/O模型
相关的理解如上
非阻塞I/O模型
相关理解如上
多路复用I/O模型一个Selector线程管理多个Socket
。常用于多线程并发场景,Java的NIO就是基于多路复用I/O模型实现的。一个Selector线程不断轮询多个Socket状态,并逐个进行事件处理和相应。Socket有读写时才通知用户线程进行I/O操作,且在内核下对Socket状态进行检查。
适用于连接数多、消息体不大的情况下;事件的响应体很大时,Selector会有瓶颈。
信号驱动I/O模型(不常用)
用户发起I/O请求后,系统为Socket注册一个信号函数。内核数据就绪,用户收到信号后,会在信号函数中调用对应的I/O读写操作完成实际的I/O请求操作。
异步I/O模型
相关理解如上。
与信号驱动模型的区别:
- 信号驱动:用户线程接收后,表示数据已经就绪,需要用户线程调用I/O函数进行实际读写操作;
- 异步I/O:用户线程接收到信号后,则表示I/O操作已经完成,数据已经复制到了用户线程,用户直接使用。
其他的I/O模型
BIO
同步阻塞,一个连接一个线程。
NIO
同步非阻塞,类似上述的多路复用I/O模式,客户端的请求会注册到一个Selector线程(多路复用器)上。适用于连接数目多且连接比较短的架构(聊天等)。
Java的NIO实现:Selector(选择器)、Channel(通道)、Buffer
Selector:用于监听多个Channel的事件,如连接打开或数据到达。
Channel:与I/O中的Stream类似(InputStream、OutputStream)
Buffer:内部通过一个连续的字节数组存储I/O删的数据。对不同数据类型,Java有不同的Buffer类实现。
如图(如有不对的请指正):
AIO
异步非阻塞,客户端的IO请求都是由OS先完成了再通知放服务器应用去启动线程处理。使用于连接数目多且较长的架构,充分调用OS参与并发操作。