Java面试重点_5. Java BIO, NIO, AIO 简明总结
文章目录
一, 何为同步和异步, 阻塞和非阻塞 ?
1.1 同步和异步
同步和异步概念以调用者的行为方式作区分;
- 当程序产生一个调用后, 如果
调用者主动等待该调用的结果
, 则称之为同步;- 当程序产生一个调用后, 如果
调用者不以主动的方式等待结果
, 而是由被调用者完成任务之后, 以某种形式(消息等等)通知调用者
, 则称之为异步;
1.2 阻塞和非阻塞
那么, 当调用产生后, 不管调用者以何种方式(同步和异步)等待这个结果, 在被调用者处理任务的那一段时间中, 调用者处于何种状态就决定了阻塞和非阻塞;
即, 阻塞和非阻塞是以被调用者处理任务的时间内"调用者的状态"作为区分的;阻塞: 当某个进程处于挂起状态(在等待其他进程的结果)时,此进程就是被阻塞了(is blocked); 当某个函数的执行过程会使当前进程blocked时, 这个函数就叫阻塞方法(blocking method).
1.3 同步阻塞, 同步非阻塞, 异步阻塞, 异步非阻塞的情况
同步方式的:
- 阻塞: 调用者调用后什么也不干,就一直在等待(阻塞中), 直到得到了想要的结果(同步);
- 非阻塞: 调用者调用后去干别的活(非阻塞), 但是因为需要主动等待结果, 所以得时不时的询问任务完成了没有(同步);
异步方式的:
- 阻塞: 调用者调用后什么也不干(阻塞中), 直到收到了被调用者的通知(异步);
- 非阻塞: 调用者调用后去干别的活(非阻塞), 当被调用者完成任务后, 就回去通知调用者(异步);
- 举个栗子:
二, BIO, NIO, AIO
2.1 Java中的IO原理
可以发现,阻塞过程主要发生在两个阶段上:
第一阶段:等待数据就绪;
第二阶段:将已就绪的数据从内核缓冲区拷贝到用户空间;
- 对应抽象到Java的Socket代码示例:
public class SocketServer {
public static void main(String[] args) throws Exception {
// 监听指定的端口
int port = 8080;
ServerSocket server = new ServerSocket(port);
// server将一直等待连接的到来
Socket socket = server.accept();
// 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
//获取数据进行处理
String message = new String(bytes, 0, len,"UTF-8");
}
// socket、server,流关闭操作,省略不表
}
}
- 可以看到这个过程和底层内核的网络IO很类似,主要体现在accept()等待从网络中的请求到来然后bytes[]数组作为缓冲区等待数据填满后进行处理。而BIO、NIO、AIO之间的区别就在于这些操作是同步还是异步,阻塞还是非阻塞。
2.2 BIO, NIO, AIO, 面向面试总结
- BIO
- BIO全称是Blocking IO,是JDK1.4之前的传统IO模型,本身是同步阻塞模式。
- 线程发起IO请求后,一直阻塞IO,直到缓冲区数据就绪后,再进入下一步操作。
- 针对网络通信都是一请求一应答的方式,虽然简化了上层的应用开发,但在性能和可靠性方面存在着巨大瓶颈,试想一下如果每个请求都需要新建一个线程来专门处理,那么在高并发的场景下,机器资源很快就会被耗尽。
- NIO
- NIO也叫Non-Blocking IO 是同步非阻塞的IO模型.
- 线程发起io请求后,立即返回(非阻塞io), 但需要定期轮询检查IO缓冲区数据是否就绪(同步);
- Java中的NIO 是new IO的意思。其实是
NIO加上IO多路复用技术
, JDK1.4 开始支持. - 普通的NIO是线程轮询查看一个IO缓冲区是否就绪,而Java中的new IO指的是线程轮询地去查看一堆IO缓冲区中哪些就绪,这是一种IO多路复用的思想。
- IO多路复用模型中,将检查IO数据是否就绪的任务,交给系统级别的select或epoll模型,由系统进行监控,减轻用户线程负担。
NIO主要由buffer、channel、selector三种技术的整合,通过零拷贝的buffer取得数据,每一个客户端通过channel在selector(多路复用器)上进行注册。服务端不断轮询channel来获取客户端的信息。channel上有connect,accept(阻塞)、read(可读)、write(可写)四种状态标识。根据标识来进行后续操作。所以一个服务端可接收无限多的channel。不需要新开一个线程。大大提升了性能。
AIO
- AIO是真正意义上的异步非阻塞IO模型,JDK7开始支持
- 之前的IO模型, 都需要用户线程定时轮询,去检查IO缓冲区数据是否就绪,占用应用程序线程资源.
- AIO是用户线程发起IO请求后立即返回(非阻塞), 由操作系统内核完成IO操作, 当缓冲区就绪后,通知用户线程或者执行回调函数。(异步)
-参考文章:
- https://www.zhihu.com/question/19732473
- https://www.javanav.com/interview/2be096a5b1d64eeda3a99da94d4b6e98.html
- https://juejin.cn/post/6844903985158045703#heading-4
- https://www.cnblogs.com/javastack/p/13222986.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)