很久没更新喽,最近build哥一直在忙着工作,忙着写小说,都忘记学习自己的本职了,哈哈,不过现在正式回归!
我们继续学习Java的IO相关内容,之前我们了解到,所谓的IO(Input/Output)就是计算机系统与外部设备之间通信的过程。
接下来我们从应用调用的过程中来分析一下整个IO的执行过程。不过在此之前,我们需要简单的了解一下整个操作系统的空间布局。为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为用户空间(User space) 和 内核空间(Kernel space ) 。
内核空间: 是操作系统内核所使用的空间,用来存储底层内核代码、数据结构以及内核级别的系统调用。内核空间拥有比较高的权限,比如文件管理、进程通信、内存管理等等。
用户空间: 用户级别的应用程序和服务分配的内存区域。它包含了应用程序的代码、数据和运行时堆栈。用户空间与内核空间相对隔离,具有较低的权限级别,不能直接访问内核空间或硬件资源。
所以说,我们想要进行 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 模型。
在传统的IO中,多以这种同步阻塞的IO模型为主,这种模型下,程序发起IO请求后,处理线程处于阻塞状态,直到请求的IO数据从内核空间拷贝到用户空间。如下图可以直观的体现整个流程(图源:沉默王二)。
如果发起IO的应用程序并发量不高的情况下,这种模型是没问题的。但很明显,当前的互联网中,很多应用都有高并发IO请求的情况,这时就迫切的需要一款高效的IO模型啦。
这种NIO模型,这个N既可以命名为NEW代表一种新型的IO模型,又可以理解为Non-Blocking,非阻塞之意。
Java NIO 是 Java 1.4 版本引入的,基于通道(Channel)和缓冲区(Buffer)进行操作,采用非阻塞式 IO 操作,允许线程在等待 IO 时执行其他任务。常见的 NIO 类有 ByteBuffer、FileChannel、SocketChannel、ServerSocketChannel 等。(图源:深入拆解Tomcat & Jetty)
虽然在应用发起IO请求时,之多多次发起,无须阻塞。但在内核将数据拷贝到用户空间时,还是会阻塞的,为了保证数据的准确性和系统的安全稳定。
在同步非阻塞IO模型下,需要通过不断的轮询去检查请求数据是否已经完成,这个过程是很耗CPU的。因此,便又诞生了I/O多路复用模型。
I/O 多路复用模型:使用操作系统提供的多路复用功能(如 select、poll、epoll 等),使得单个线程可以同时处理多个 I/O 事件。当某个连接上的数据准备好时,操作系统会通知应用程序。这样,应用程序可以在一个线程中处理多个并发连接,而不需要为每个连接创建一个线程。(图源:沉默王二)
AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
以上BIO、NIO、AIO三种常见的IO模型是Java面试中最常考的,大家一定要记住其各自的特点和作用。