18、你能聊聊BIO、NIO、AIO分别都是啥?有什么区别?
00 分钟
2022-9-2
1、面试题
nio、bio、aio都是什么以及有什么区别?说说nio的原理?
2、面试官心里分析
如果聊io这块,我就必问这个问题,因为io的那些过于基础的知识,各种流的使用,是用来考察应届生和培训班刚出来的同学的,正常问一个有经验的开发人员,io这块就是聊聊几种io模式,以及同步、异步、阻塞和非阻塞几种io的概念。
3、面试题剖析
3.1 BIO(Blocking I/O)
这个其实就是最传统的网络通信模型,就是BIO,同步阻塞式IO,简单来说大家如果参加过几个月的培训班儿应该都知道这种BIO网络通信方式。就是服务端创建一个ServerSocket,然后客户端用一个Socket去连接那个ServerSocket,然后ServerSocket接收到一个Socket的连接请求就创建一个Socket和一个线程去跟那个Socket进行通信。
然后客户端和服务端的socket,就进行同步阻塞式的通信,客户端socket发送一个请求,服务端socket进行处理后返回响应,响应必须是等处理完后才会返回,在这之前啥事儿也干不了,这可不就是同步么。
这种方式最大的坑在于,每次一个客户端接入,都是要在服务端创建一个线程来服务这个客户端的,这会导致大量的客户端的时候,服务端的线程数量可能达到几千甚至几万,几十万,这会导致服务器端程序的负载过高,最后崩溃死掉。
要么你就是搞一个线程池,固定线程数量来处理请求,但是高并发请求的时候,还是可能会导致各种排队和延时,因为没那么多线程来处理。

运行结果

使用终端命令
notion image
3.2 NIO(Non-Blocking I/O)
JDK 1.4中引入了NIO,这是一种同步非阻塞的IO,基于Reactor模型。
NIO中有一些概念:
比如Buffer,缓冲区的概念,一般都是将数据写入Buffer中,然后从Buffer中读取数据,有IntBuffer、LongBuffer、CharBuffer等很多种针对基础数据类型的Buffer。
还有Channel,NIO中都是通过Channel来进行数据读写的。
包括Selector,这是多路复用器,selector会不断轮询注册的channel,如果某个channel上发生了读写事件,selector就会将这些channel获取出来,我们通过SelectionKey获取有读写事件的channel,就可以进行IO操作。一个Selector就通过一个线程,就可以轮询成千上万的channel,这就意味着你的服务端可以接入成千上万的客户端。
这块其实相当于就是一个线程处理大量的客户端的请求,通过一个线程轮询大量的channel,每次就获取一批有事件的channel,然后对每个请求启动一个线程处理即可。
这里的核心就是非阻塞,就那个selector一个线程就可以不停轮询channel,所有客户端请求都不会阻塞,直接就会进来,大不了就是等待一下排着队而已。
这里的核心就是因为,一个客户端不是时时刻刻都要发送请求的,没必要死耗着一个线程不放吧,所以NIO的优化思想就是一个请求一个线程。只有某个客户端发送了一个请求的时候,才会启动一个线程来处理。
所以为啥是非阻塞呢?因为无论多少客户端都可以接入服务端,客户端接入并不会耗费一个线程,只会创建一个连接然后注册到selector上去罢了,一个selector线程不断的轮询所有的socket连接,发现有事件了就通知你,然后你就启动一个线程处理一个请求即可,但是这个处理的过程中,你还是要先读取数据,处理,再返回的,这是个同步的过程。
所以NIO是同步非阻塞的。
工作线程,从channel里读数据,是同步的,是工作线程自己去干这个事儿,卡在那儿,专门干读数据的这个活儿,数据没读完,你就卡死在这儿了;然后往channel里写数据,也是你自己去干这个事儿,卡死在这儿了,数据没写完,你就卡在这儿了
3.3 AIO (Asynchronous I/O)
AIO是基于Proactor模型的,就是异步非阻塞模型。
每个连接发送过来的请求,都会绑定一个buffer,然后通知操作系统去异步完成读,此时你的程序是会去干别的事儿的,等操作系统完成数据读取之后,就会回调你的接口,给你操作系统异步读完的数据。
然后你对这个数据处理一下,接着将结果往回写。
写的时候也是给操作系统一个buffer,让操作系统自己获取数据去完成写操作,写完以后再回来通知你。
工作线程,读取数据的时候,是说,你提供给操作系统一个buffer,空的,然后你就可以干别的事儿了,你就把读数据的事儿,交给操作系统去干,操作系统内核,读数据将数据放入buffer中,完事儿了,来回调你的一个接口,告诉你说,ok,buffer交给你了,这个数据我给你读好了
写数据的时候也是一样的的,把放了数据的buffer交给操作系统的内核去处理,你就可以去干别的事儿了,操作系统完成了数据的写之后,回会来回调你,告诉你说,ok,哥儿们,你交给我的数据,我都给你写回到客户端去了
3.4 同步阻塞、同步非阻塞、异步非阻塞
但是这里为啥叫BIO是同步阻塞呢?这个其实不是针对网络编程模型来说的,是针对文件IO操作来说的,因为用BIO的流读写文件,是说你发起个IO请求直接hang死,必须等着搞完了这次IO才能返回
BIO的这个同步阻塞,不是完全针对的网络通信模型去说的,针对的是磁盘文件的IO读写,FileInputStream,BIO,卡在那儿,直到你读写完成了才可以
NIO为啥是同步非阻塞?就是说通过NIO的FileChannel发起个文件IO操作,其实发起之后就返回了,你可以干别的事儿,这就是非阻塞,但是接下来你还得不断的去轮询操作系统,看IO操作完事儿了没有。
你呢也可以使用FileChannel这种NIO的模型,去读写磁盘文件,读数据,发起读数据的请求之后,你不是阻塞住的,你可以干别的事儿,但是你在干别的事儿的同时,还得来时不时的自己去轮询操作系统读数据的状态,看看人家读好了没有
AIO为啥是异步非阻塞?就是说通过AIO发起个文件IO操作之后,你立马就返回可以干别的事儿了,接下来你也不用管了,操作系统自己干完了IO之后,告诉你说ok了。同步就是自己还得主动去轮询操作系统,异步就是操作系统反过来通知你。
你也可以基于AIO的文件读写的api去读写磁盘文件,你发起一个文件读写的操作之后,交给操作系统,你就不去管他了,直到操作系统自己完成之后,会来回调你的一个接口,通知你说,ok,这个数据读好了,那个数据写完了
3.5 BIO、NIO、AIO的demo代码

评论