Java 常见 I/O 模式

  • 什么是 I/O ?

    • 从计算机结构角度解释:根据冯.诺依曼结构,计算机结构分为 5 大部分:运算器、控制器、存储器、输入设备、输出设备。输入设备向计算机输入数据,输出设备接收计算机输出的数据 。I/O 描述了计算机系统与外部设备之间通信的过程。为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为 用户空间(User space) 和 内核空间(Kernel space )。我们平常运行的应用程序都是运行在用户空间,只有内核空间才能进行系统态级别的资源有关的操作,比如如文件管理、内存管理等等。也就是说,用户想要执行I/O操作由于没有权限,必须通过操作系统调用来间接访问内核空间。
    • 从应用程序的视角: 我们的应用程序对操作系统的内核发起 IO 调用(系统调用),操作系统负责的内核执行具体的 IO 操作。也就是说,我们的应用程序实际上只是发起了 IO 操作的调用而已,具体 IO 的执行是由操作系统的内核来完成的。当应用程序发起 I/O 调用后,会经历两个步骤:1. 内核等待 I/O 设备准备好数据 2. 内核将数据从内核空间拷贝到用户空间。
  • 常见的IO模型?

    • UNIX 系统下, IO 模型一共有 5 种: 同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O ,Java中常见三种IO模型:BIO (Blocking I/O) 同步阻塞IO、NIO (Non-blocking/New I/O) I/O 多路复用、AIO (Asynchronous I/O)异步 I/O。
  • 什么是同步和异步、阻塞和非阻塞?

    • 同步是指一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成。异步是指不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作。然后继续执行下面代码逻辑,只要自己完成了整个任务就算完成了(异步一般使用状态、通知和回调)。
    • 阻塞是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务(大部分代码都是这样的)非阻塞是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回(继续执行下面代码,或者重试机制走起)。也就是说:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成
  • 同步阻塞I/O

    • 应用程序中进程在发起IO调用后至内核执行IO操作返回结果之前,若发起系统调用的线程一直处于等待状态,则此次IO操作为阻塞IO。内核从准备数据到拷贝数据到用户空间的两个阶段期间用户调用线程选择阻塞等待数据返回。

      在这里插入图片描述

  • 同步非阻塞(NIO)

    • 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 模型中,应用程序会一直发起 read 调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。但是,这种 IO 模型同样存在问题:应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的

  • I/O多路复用

    • IO 多路复用模型中,线程首先发起 select 调用(内核提供的系统调用,它支持一次查询多个系统调用的可用状态 ),询问内核数据是否准备就绪,等内核把数据准备好了,用户线程再发起 read 调用。read 调用的过程(数据从内核空间->用户空间)还是阻塞的。 IO 多路复用模型,**通过减少无效的系统调用,减少了对 CPU 资源的消耗 **。Java 中的 NIO ,有一个非常重要的选择器 ( Selector ) 的概念,也可以被称为 多路复用器。通过它,只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后,才会为其服务。

  • 异步I/O

    • AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。异步IO:用户进程发出系统调用后立即返回,内核等待数据准备完成,然后将数据拷贝到用户进程缓冲区,然后主动发送信号告诉用户进程IO操作执行完毕

  • 总结

    • BIO:用户进程发出系统调用后,线程阻塞等待内核处理数据完成。
    • NIO:通过选择器监听通道,非阻塞,等待数据准备好后再进行读取。
    • AIO:用户进程发出调用后,立即继续执行其他操作,内核自动通知回调。

猜你喜欢

转载自blog.csdn.net/cj151525/article/details/129861723