一、IO与NIO
1、IO
简介:数据的以stream(流)的方式进行传输,流为IO流。IO是面向流的
分类
1)按流的方向:输入流、输出流
2)按流的性质:字节流、字符流
3)按流的角色:节点流、处理流
2、NIO
简介:数据的以块的方式进行传输,数据传输受channel(通道)、buffer(缓冲区)、selecter(监控区)调度。与IO的不同是,NIO是面向缓冲区的
channel:传输数据的通道
buffer:数据的缓冲区
selecter:监控服务端的区域
调度方式
当client(客户端)线程发送NIO请求,selecter会监控server(服务端)的数据是否准备好进行读写,若时没有准备好(其他线程在使用),client线程则回去干其他事,不会阻塞,selecer会持续监听server中资源的状态。若资源做好了被读写的准备,server内核就会将该资源通过buffer放入channel,client的线程经过读取channel放入buffer中的数据。
经典实例
多路复用
IO
模型
多路复用
IO
模型是目前使用得比较多的模型。
Java NIO
实际上就是多路复用
IO
。在多路复用
IO
模型中,会有一个线程不断去轮询多个 socket 的状态,只有当
socket
真正有读写事件时,才真正调用实际的
IO
读写操作。因为在多路复用
IO
模型中,只需要使用一个线程就可 以管理多个socket
,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有
socket
读写事件进行时,才会使用
IO 资源,所以它大大减少了资源占用。在
Java NIO
中,是通过
selector.select()
去查询每个通道是否有到达事件,如果没有事件,则一直 阻塞在那里,因此这种方式会导致用户线程的阻塞。多路复用 IO
模式,通过一个线程就可以管理多个
socket
,只有当
socket
真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用
IO
比较适合连接数比较多的情况。
另外多路复用
IO
为何比非阻塞
IO
模型的效率高是因为在非阻塞
IO
中,不断地询问
socket
状态时通过用户线程去进行的,而在多路复用 IO 中,轮询每个
socket
状态是内核在进行的,这个效率要比用户线程要高的多。
2、其他IO模型
BIO:同步阻塞IO
client线程在进行IO问时,若访问的资源被占用,则client线程会阻塞等待。线程释放cpu,若资源准备好了且线程再次获取cpu则会对该资源进行访问。
非阻塞IO
client线程在进行IO问时,若访问的资源被占用,则client线程不会释放cpu,会一直发送请求,资源一旦空闲就马上得到访问机会。该方式会极大的浪费cpu资源。不推荐使用。
信号驱动 IO 模型
在信号驱动
IO
模型中,当用户线程发起一个
IO
请求操作,会给对应的
socket
注册一个信号函数,然后用户线程会继续执行,当内核数据 就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用 IO
读写操作来进行实际的
IO
请求操作。
异步 IO 模型
异步
IO
模型才是最理想的
IO
模型,在异步
IO
模型中,当用户线程发起
read
操作之后,立刻就可以开始去做其它的事。而另一方面,从 内核的角度,当它受到一个 asynchronous read
之后,它会立刻返回,说明
read
请求已经成功发起了,因此不会对用户线程产生任何 block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它 read 操作完成了。也就说用户线程完全不需要实际的整个
IO
操作是如何进行的, 只需要先发起一个请求,当接收内核返回的成功信号时表 示 IO
操作已经完成,可以直接去使用数据了。