IO模型
io流指数据的流从源头流到目的地
按单位大小:字节流 字符流
按流的方向:输出流 输入流
BIO阻塞 NIO非阻塞
BIO面向流 NIO面向缓冲
BIO同步阻塞
适用于连接数目较小且固定的架构
一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理。
线程发出请求后,内核会查看数据是否就绪,没有就绪就会等待数据就绪,线程处于阻塞状态,线程交出cpu。数据就绪后,内核将数据拷贝到线程并返回结果给线程,此时线程解除阻塞状态
当服务端需要处理多个客户端的通信请求时,服务端引入线程,当客户端每发起一个请求,服务端就创建一个新的 线程来处理该客户端的请求。
NIO同步非阻塞
适用于连接数目多且连接比较短的架构
一个线程可以处理多个请求
客户端发送的连接请求都会注册到多路复用器selector,selector轮询到连接有I/O请求就进行处理
Buffer缓冲区
一块可写入数据,可读取数据的内存,底层是连续数组,不同于BIO要么是输入流要么是输出流
在 NIO 中,Buffer 是一个顶层父类,它是一个抽象类,常用的 Buffer 的子类有:ByteBuffer、IntBuffer、 CharBuffer、 LongBuffer、 DoubleBuffer、FloatBuffer、ShortBuffer(Boolean没有对应的Buffer类)
客户端发送数据,先将数据存入Buffer中,再将Buffer中的内容写入通道。
服务端接收数据必须通过Channel将数据读入Buffer中,再从Buffer中取出数据
Buffer中的概念
- 容量(capacity) 作为一个内存块,Buffer具有一定的大小–》容量,缓冲区的容量不能为负,创建后也不允许修改容量大小
- 限制(limit) 缓冲区中可以操作数据的大小(limit后的数据不可以进行读写)。 缓冲区的限制不能为负,也不能大于容量值
- 写入时,limit等于buffer的容量;读取时,limit等于已写入的数据量
- 位置(position) 下一个要读取/写入的数据的索引。 位置不能为负,且不能大于limit
- 标记(mark)与重置(reset) 标记作为一个索引,通过mark()方法指定Buffer中一个特定的位置,之后可通过reset()方法恢复到这个position
- 以上的值遵守不定式: 0 <= mark <= position <= limit <= capacity
Channel通道
一个channel对应一个buffer,表示打开到IO设备,程序切换到哪个channel由事件决定
可以同时读取和写入数据(非阻塞),支持异步读写,不同于流只能单向操作
NIO 中的 Channel 的主要实现有:
-
FileChannel --》文件IO
-
DatagramChannel --》 UDP 协议网络通信
-
SocketChannel --》 TCP协议网络通信
-
ServerSocketChannel --》监听TCP连接
Selector选择器
一个selector对应多个channel,根据不同事件在各个通道上切换,确定哪些channel已经准备好进行读取/写入。
用一个单线程就可以管理多个通道,减少了系统开销,不用去维护多个线程,避免了多线程之间上下文切换导致的开销
NIO的核心在于channel和buffer。要使用NIO系统需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。
channel负责传输,buffer负责存取数据
AIO异步非阻塞
适用于连接数目多且连接比较长的架构
当线程发起read()操作后,立刻就可以去执行其他操作。等到内核返回成功信号表示IO操作已完成,此时线程可以直接使用数据