本文节选自《Java 面试进阶指北 打造集体的技术竞争力》
面试中常常喜爱问的一个问题,因为通过这个问题,面试官能够顺便理解一下你的操作系统的程度。
IO 模型这块的确挺难了解的,须要太多计算机底层常识。写这篇文章用了挺久,就十分心愿能把我所晓得的讲进去吧! 心愿敌人们能有收货!为了写这篇文章,还翻看了一下《UNIX 网络编程》这本书,太难了,我滴乖乖!心痛~
集体能力无限。如果文章有任何须要补充 / 欠缺 / 批改的中央,欢送在评论区指出,共同进步!
前言
I/O 始终是很多小伙伴难以了解的一个知识点,这篇文章我会将我所了解的 I/O 讲给你听,心愿能够对你有所帮忙。
I/O
何为 I/O?
I/O(Input/Outpu)即 输出/输入。
咱们先从计算机构造的角度来解读一下 I/O。
依据冯. 诺依曼结构,计算机构造分为 5 大部分:运算器、控制器、存储器、输出设施、输出设备。
输出设施(比方键盘)和输出设备(比方显示屏)都属于外部设备。网卡、硬盘这种既能够属于输出设施,也能够属于输出设备。
输出设施向计算机输出数据,输出设备接管计算机输入的数据。
从计算机构造的视角来看的话,I/O 形容了计算机系统与外部设备之间通信的过程。
咱们再先从应用程序的角度来解读一下 I/O。
依据大学里学到的操作系统相干的常识:为了保障操作系统的稳定性和安全性,一个过程的地址空间划分为 用户空间(User space) 和 内核空间(Kernel space)。
像咱们平时运行的应用程序都是运行在用户空间,只有内核空间能力进行零碎态级别的资源无关的操作,比方如文件治理、过程通信、内存治理等等。也就是说,咱们想要进行 IO 操作,肯定是要依赖内核空间的能力。
并且,用户空间的程序不能间接拜访内核空间。
当想要执行 IO 操作时,因为没有执行这些操作的权限,只能发动零碎调用申请操作系统帮忙实现。
因而,用户过程想要执行 IO 操作的话,必须通过 零碎调用 来间接拜访内核空间
咱们在平时开发过程中接触最多的就是 磁盘 IO(读写文件) 和 网络 IO(网络申请和相应)。
从应用程序的视角来看的话,咱们的应用程序对操作系统的内核发动 IO 调用(零碎调用),操作系统负责的内核执行具体的 IO 操作。也就是说,咱们的应用程序实际上只是发动了 IO 操作的调用而已,具体 IO 的执行是由操作系统的内核来实现的。
当应用程序发动 I/O 调用后,会经验两个步骤:
- 内核期待 I/O 设施筹备好数据
- 内核将数据从内核空间拷贝到用户空间。
有哪些常见的 IO 模型?
UNIX 零碎下,IO 模型一共有 5 种:同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用 、 信号驱动 I/O 和 异步 I/O。
这也是咱们常常提到的 5 种 IO 模型。
Java 中 3 种常见 IO 模型
BIO (Blocking I/O)
BIO 属于同步阻塞 IO 模型。
同步阻塞 IO 模型中,应用程序发动 read 调用后,会始终阻塞,直到在内核把数据拷贝到用户空间。
在客户端连贯数量不高的状况下,是没问题的。然而,当面对十万甚至百万级连贯的时候,传统的 BIO 模型是无能为力的。因而,咱们须要一种更高效的 I/O 解决模型来应答更高的并发量。
NIO (Non-blocking/New I/O)
Java 中的 NIO 于 Java 1.4 中引入,对应 java.nio
包,提供了 Channel
, Selector
,Buffer
等形象。NIO 中的 N 能够了解为 Non-blocking,不单纯是 New。它反对面向缓冲的,基于通道的 I/O 操作方法。对于高负载、高并发的(网络)利用,应应用 NIO。
Java 中的 NIO 能够看作是 I/O 多路复用模型。也有很多人认为,Java 中的 NIO 属于同步非阻塞 IO 模型。
跟着我的思路往下看看,置信你会失去答案!
咱们先来看看 同步非阻塞 IO 模型。
同步非阻塞 IO 模型中,应用程序会始终发动 read 调用,期待数据从内核空间拷贝到用户空间的这段时间里,线程仍然是阻塞的,直到在内核把数据拷贝到用户空间。
相比于同步阻塞 IO 模型,同步非阻塞 IO 模型的确有了很大改良。通过轮询操作,防止了始终阻塞。
然而,这种 IO 模型同样存在问题:应用程序一直进行 I/O 零碎调用轮询数据是否曾经筹备好的过程是非常耗费 CPU 资源的。
这个时候,I/O 多路复用模型 就上场了。
IO 多路复用模型中,线程首先发动 select 调用,询问内核数据是否准备就绪,等内核把数据筹备好了,用户线程再发动 read 调用。read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
目前反对 IO 多路复用的零碎调用,有 select,epoll 等等。select 零碎调用,是目前简直在所有的操作系统上都有反对
- select 调用:内核提供的零碎调用,它反对一次查问多个零碎调用的可用状态。简直所有的操作系统都反对。
- epoll 调用:linux 2.6 内核,属于 select 调用的加强版本,优化了 IO 的执行效率。
IO 多路复用模型,通过缩小有效的零碎调用,缩小了对 CPU 资源的耗费。
Java 中的 NIO,有一个十分重要的 选择器 (Selector) 的概念,也能够被称为 多路复用器。通过它,只须要一个线程便能够治理多个客户端连贯。当客户端数据到了之后,才会为其服务。
AIO (Asynchronous I/O)
AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2, 它是异步 IO 模型。
异步 IO 是基于事件和回调机制实现的,也就是利用操作之后会间接返回,不会梗塞在那里,当后盾解决实现,操作系统会告诉相应的线程进行后续的操作。
目前来说 AIO 的利用还不是很宽泛。Netty 之前也尝试应用过 AIO,不过又放弃了。这是因为,Netty 应用了 AIO 之后,在 Linux 零碎上的性能并没有多少晋升。
最初,来一张图,简略总结一下 Java 中的 BIO、NIO、AIO。
参考
- 《深刻拆解 Tomcat & Jetty》
- 如何实现一次 IO:https://llc687.top/post/ 如何实现一次 -io/
- 程序员应该这样了解 IO:https://www.jianshu.com/p/fa7bdc4f3de7
- 10 分钟看懂,Java NIO 底层原理:https://www.cnblogs.com/crazy…
- IO 模型知多少 | 实践篇:https://www.cnblogs.com/sheng…
- 《UNIX 网络编程 卷 1;套接字联网 API》6.2 节 IO 模型
举荐
《JavaGuide 面试突击版》PDF 版本。图解计算机根底 PDF 版。