今天我们来聊 Java IO 模型,BIO、NIO、AIO 三种常见 IO 模型
一、IO 调用过程
接下来我们从应用调用的过程中来分析一下整个 IO 的执行过程。不过在此之前,我们需要简单的了解一下整个操作系统的空间布局。为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为用户空间(User space) 和 内核空间(Kernel space ) 。
内核空间: 是操作系统内核所使用的空间,用来存储底层内核代码、数据结构以及内核级别的系统调用。内核空间拥有比较高的权限,比如文件管理、进程通信、内存管理等等。
用户空间: 用户级别的应用程序和服务分配的内存区域。它包含了应用程序的代码、数据和运行时堆栈。用户空间与内核空间相对隔离,具有较低的权限级别,不能直接访问内核空间或硬件资源。
![](https://static001.geekbang.org/infoq/71/71f6502cadc9711352f18006739a66af.png)
所以说,我们想要进行 IO 操作,一定是要依赖内核空间的能力。平常开发过程中接触最多的就是磁盘 IO(读写文件) 和 网络 IO(网络请求和响应)。
执行步骤:
应用程序发起 IO 请求;
系统内核接受到系统调用请求;
内核等待数据准备;
内核将数据从内核空间拷贝到用户空间;
IO 输出给应用程序。
二、IO 常用模型
在 UNIX 系统中,我们所提到的 IO 模型一般是这四种:同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O。
不过,在日常使用中,我们常用的多为 BIO(Blocking I/O)
:同步阻塞 IO 模型、NIO (Non-blocking/New I/O)
:同步非阻塞 IO 模型、AIO (Asynchronous I/O)
:异步 IO 模型。
2.1 BIO (Blocking I/O)
在传统的 IO 中,多以这种同步阻塞的 IO 模型为主,这种模型下,程序发起 IO 请求后,处理线程处于阻塞状态,直到请求的 IO 数据从内核空间拷贝到用户空间。如下图可以直观的体现整个流程(图源:沉默王二)。
![](https://static001.geekbang.org/infoq/d6/d66e4770a1a1f86474883c6bed2b4c3a.png)
如果发起 IO 的应用程序并发量不高的情况下,这种模型是没问题的。但很明显,当前的互联网中,很多应用都有高并发 IO 请求的情况,这时就迫切的需要一款高效的 IO 模型啦。
2.2 NIO (Non-blocking/New I/O)
这种 NIO 模型,这个 N 既可以命名为 NEW 代表一种新型的 IO 模型,又可以理解为 Non-Blocking,非阻塞之意。
Java NIO 是 Java 1.4 版本引入的,基于通道(Channel)和缓冲区(Buffer)进行操作,采用非阻塞式 IO 操作,允许线程在等待 IO 时执行其他任务。常见的 NIO 类有 ByteBuffer、FileChannel、SocketChannel、ServerSocketChannel 等。(图源:深入拆解 Tomcat & Jetty)
![](https://static001.geekbang.org/infoq/1f/1f15f248049cf020a598ae46ffa3f793.png)
虽然在应用发起 IO 请求时,之多多次发起,无须阻塞。但在内核将数据拷贝到用户空间时,还是会阻塞的,为了保证数据的准确性和系统的安全稳定。
2.3 I/O 多路复用模型
在同步非阻塞 IO 模型下,需要通过不断的轮询去检查请求数据是否已经完成,这个过程是很耗 CPU 的。因此,便又诞生了 I/O 多路复用模型。
I/O 多路复用模型:使用操作系统提供的多路复用功能(如 select、poll、epoll 等),使得单个线程可以同时处理多个 I/O 事件。当某个连接上的数据准备好时,操作系统会通知应用程序。这样,应用程序可以在一个线程中处理多个并发连接,而不需要为每个连接创建一个线程。(图源:沉默王二)
![](https://static001.geekbang.org/infoq/39/396b10feebeae26de63c37ea0a86f094.png)
2.4 AIO (Asynchronous I/O)
AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
![](https://static001.geekbang.org/infoq/f3/f344c4bb881a84f0cd6365ef84f6f7d6.png)
总结
以上 BIO、NIO、AIO 三种常见的 IO 模型是 Java 面试中最常考的,大家一定要记住其各自的特点和作用。
阻塞 I/O:应用程序执行 I/O 操作时,会一直等待数据传输完成,期间无法执行其他任务。
非阻塞 I/O:应用程序执行 I/O 操作时,如果数据未准备好,立即返回错误状态,不等待数据传输完成,可执行其他任务。
异步 I/O:应用程序发起 I/O 操作后,内核负责数据传输过程,完成后通知应用程序。应用程序无需等待数据传输,可执行其他任务。
文章转载自:JavaBuild
评论