BIO、NIO、AIO
问这个问题,通常是考察你对 Web 应用高并发的理解
预备知识
● 开发 Web 应用,肯定分成客户端和服务器。
● 客户端与服务器交互,肯定得做这么几件事:
○ 服务器线程等待有客户端连接上来
○ 客户端真的连上来了,建立连接
○ 客户端没有向服务器发送请求,此时服务器线程需要等待数据准备好
○ 客户端向服务器发送请求,需要将请求数据从网卡复制到系统内存
● 上面 a. c. 这两个阶段,没有客户端连接,没有数据请求,这时是否需要一个线程时刻盯着?
○ 如果需要占用一个线程,那么就称线程被阻塞
○ 如果不需要线程盯着,线程可以腾出手来去干别的活,那么就称线程非阻塞
● d. 阶段的数据复制,不会用到 CPU,也就是不会用到线程,同样也存在线程阻塞还是线程非阻塞两种情况
BIO(阻塞 I/O)
● 是指 b. c. d.这几个阶段,线程都得阻塞,腾不出手干别的,即使此时它无所事事
● 高并发下,阻塞线程多了,处理连接、处理请求的能力就会大受影响
○ 增加线程不可行,毕竟线程是有限资源,这是成本问题
○ 不增加线程也不行,没有新线程,没人去处理新连接,处理新请求
NIO(非阻塞 I/O)
● 是指 b. c. 这两个阶段,线程可以不阻塞,腾出手干别的(怎么干别的,要靠多路复用)
● 非阻塞 I/O 通常结合多路复用技术一起使用,能够在高并发下用少量线程处理大量请求
○ 多路复用是以面向事件的方式处理连接、处理请求,有事件发生才去处理,没有事件则不会占用线程
○ 使用了多路复用技术后,新客户端来了要连接,客户端发来了新请求,都会产生事件,把这些事件交给一个线程去统一处理就行了
○ 线程不会在高并发下存在无事可做的现象,它被充分压榨,利用率高
AIO(异步 I/O)
● NIO 在 d. 这个阶段,线程仍需阻塞,不能被解放出来干其它活
● AIO 则更进一步,只需要提前准备好回调函数,在数据复制时线程被解放,该干嘛干嘛,等数据复制完毕,由系统使用另外线程来调用回调函数做后续处理
● AIO 在 Linux 下本质还是用多路复用技术来实现
小结
● BIO 并发性低,但代码更容易编写
● NIO 并发性高,不过代码编写困难
● AIO 并发性在 Linux 下没有本质提高,用的人少
● 【进阶】Java 21 起,正式支持虚拟线程
○ 配合虚拟线程时,仍然是以 BIO 方式来编写代码,代码编写容易
○ 虚拟线程非常廉价,线程不是不够吗,可劲加就行(不用担心线程闲置问题)
○ Java 21 重新实现了网络 API,虚拟线程底层也会配合多路复用机制,在代码易编写的情况下,兼具高性能
P.S.
● B 是 Blocking 阻塞
● N 是 Non-Blocking 非阻塞
● A 是 Asynchronous 异步