Java IO 系列总纲&系统IO模型

3,272 阅读3分钟

在Android开发中,不可避免的会接触到IO,抛开系统部分的IO,在应用开发领域,仍然会接触到IO,诸如:

  • 文件读写
  • 网络通信

或许您在开发中不再直接使用JDK中的API完成IO部分的功能,但仍有必要了解相关知识。

JAVA的IO,通过虚拟机建立在操作系统的IO之上,在梳理JAVA的IO时,可适当了解操作系统部分IO的相关知识,但本系列不会深究。

大纲

本系列中,计划包含以下内容:

  • JAVA 经典IO 一篇
  • JAVA NIO 1-3篇
  • OK-IO 1篇
  • Linux系统中的IO(如有必要)
  • IO模型概览 本文顺带

下图表现了一个冯诺依曼机的结构:

desc

在操作系统中,IO操作会涉及到 用户空间、内核空间的切换 ,以及 内核空间、用户空间之间的数据拷贝 ,接下来就常见的IO模型,简单了解下概念和设计理念。

注:不同操作系统在实现时会存在一定差异,不做深究

IO模型

  • 阻塞I/O(blocking I/O)
  • 非阻塞I/O(non-blocking I/O)
  • I/O复用(I/O multiplexing)
  • 信号驱动式I/O(signal-driven I/O)
  • 异步I/O(asynchronous I/O)

阻塞I/O(blocking I/O)

阻塞IO、BIO、Blocking IO

内核IO操作 彻底完成后,才返回 用户空间 执行应用的操作。

此过程中,用户空间程序的执行状态是阻塞的,程序需等到IO操作彻底完成。

以读为例,示意图如下

desc

非阻塞I/O(non-blocking I/O)

注意,此处不要与 JAVA的nio包 内容混淆

非阻塞IO

相比于BIO,NIO中 数据等待阶段 是非阻塞的,操作系统不会挂起应用。

类似于JAVA中使用Future进行非阻塞多线程编程,以读为例,应用 轮询 内核,数据是否完成,数据准备就绪后,发起系统调用获取数据,系统调用的过程中,应用阻塞。

轮询: 应用进程对非阻塞描述符循环发送系统调用,以查看某个操作是否就绪

以读为例,示意图如下

desc

I/O复用(I/O multiplexing)

I/O复用

经典的Reactor设计。进程通过将一个或者多个操作阻塞在 select 阶段,select可以帮我们检测 fd(文件操作符) 是否处于就绪状态。

如果有数据准备好,就返回可操作的信息,再进行进一步地读写操作

当需要观测的fd很多时,数据准备的占比可能变高,轮询的收益会降低,而多路复用会得到更高的收益。

以读为例,示意图如下

desc

信号驱动式I/O(signal-driven I/O)

信号驱动式I/O

在数据准备阶段,不再阻塞等待,内核准备好数据后,通过信号通知用户空间,用户空间的应用发起系统调用,阻塞获取数据

以读为例,示意图如下

desc

异步I/O(asynchronous I/O)

异步I/O

不同于信号驱动式I/O,在数据等待完成后,进行内核到用户空间的数据拷贝,完成后信号通知应用程序处理数据

desc