最近在面试时,千锋有好几个学生遇到了这样的一个问题,BIO、NIO、AIO分别是什么?有什么区别?那这个问题该怎么回答呢?今天千锋给大家简单梳理一下这个问题。
一. BIO 同步阻塞式原理解析
简介
传统的网络通讯模型,就是BIO,属于同步阻塞的IO模型。比如我们熟悉的Socket通信。
Socket服务端创建过程:
服务端创建一个ServerSocket;
客户端用一个Socket去连接服务端的那个ServerSocket;
ServerSocket接收到了一个的连接请求,就创建一个Socket和一个线程去跟那个Socket进行通讯。
客户端和服务端进行阻塞式通信过程:
客户端发送一个请求;
服务端Socket进行处理后返回响应;
在响应返回前,客户端那边就阻塞等待,任何事情都做不了。
BIO缺点
每次一个客户端接入进来,都需要在服务端创建一个线程来服务这个客户端。这样当大量客户端过来的时候,就会造成服务端的线程数量可能达到了几千甚至几万,这样就可能会造成服务端过载过高,最后崩溃死掉。
BIO模型图
Acceptor
传统IO模型中,网络服务的设计模式有两种比较经典的设计模式:
一个是多线程;
一种是依靠线程池来进行处理。
如果是基于多线程的模式来的话,就是这样的模式,这种也是Acceptor线程模型。
二. NIO 同步非阻塞IO
简介
基于Reactor模型来实现的,相当于,一个线程处理大量的客户端的请求,通过一个线程轮询大量channel,每次就获取一批有事件的channel,然后对每个请求启动一个线程处理即可。
这里的核心就是非阻塞,selector一个线程就可以不停轮询channel,所有客户端请求都不会阻塞,最多就是等待下一轮的轮询。
NIO--优化BIO的核心
一个客户端并不是时时刻刻都有数据进行交互,所以更没有必要死耗着一个线程不放,所以客户端选择了让线程歇一歇,只有客户端有相应的操作的时候才发起通知,再创建一个线程来处理请求。
NIO模型图
Reactor模型
三. AIO 异步非阻塞IO
简介
AIO基于Proactor模型实现,分为发送请求和读取数据两个步骤:
发送请求:处理每个连接发送过来的请求。
每个请求都会绑定一个Buffer;
通知操作系统去完成异步的读(这个时间你就可以去做其他的事情);
调用你的接口;
返回异步读完的数据。
读取数据:将数据往回写。
一个Buffer,让操作系统去完成写。
发送请求和读取数据的主要区别在于:
将数据写入的缓冲区后,剩下的交给操作系统去完成;
操作系统写回数据也是一样,写到Buffer里面,完成后再通知客户端来进行读取数据。
AIO模型图
四. 3个模型的一些问题
同步阻塞--为什么说BIO是同步阻塞的呢?
针对磁盘文件读写IO操作来说,因为用BIO的流读写文件,例如FileInputStrem,必须等着完成了这次IO才能返回。
同步非阻塞--为什么说NIO为啥是同步非阻塞?
因为无论多少客户端都可以接入服务端,客户端接入并不会耗费一个线程,只会创建一个连接,然后注册到selector上去,一个selector线程不断的轮询所有的socket连接,发现有事件了就通知你,然后你就启动一个线程处理一个请求即可,这个过程的话就是非阻塞的。
但是这个处理的过程中,你还是要先读取数据,处理,再返回的,这是个同步的过程。
异步非阻塞--为什么说AIO是异步非阻塞?
当基于AIO的api去读写文件时,发起一个请求之后,等读写完成后, 操作系统会来回调你的接口, 告诉你操作完成。在这期间不需要等待, 也不需要去轮询判断操作系统完成的状态,你可以去干其他的事情。
同步还得主动去轮询操作系统,异步就是操作系统反过来通知你,所以说 AIO就是异步非阻塞的。