IO模型
约 1249 字大约 4 分钟
2025-09-04
BIO (Blocking I/O)
BIO,即 Blocking I/O,是 Java 最传统的 I/O 模型,基于 java.io 包。它采用流模型实现,交互方式是同步且阻塞的。
- 同步阻塞:当应用程序进行读写操作时,在数据完全读入或写入完成之前,线程会一直被阻塞,无法执行其他任务。这确保了操作的线性顺序和可靠性。
- 流式:数据以字节流的形式进行传输。
- 优点:
- 代码实现简单直观,易于理解和开发。
- 缺点:
- I/O 效率和扩展性低下。每个客户端连接都需要一个独立的线程处理,当并发连接数增多时,会创建大量线程,导致上下文切换开销大,资源消耗高,容易成为系统性能瓶颈。
NIO (Non-Blocking I/O)
NIO,即 Non-Blocking I/O,是 Java 1.4 引入的 java.nio 包提供的 I/O 模型。它提供了 Channel(通道)、Selector(选择器)和 Buffer(缓冲区)等核心抽象,旨在构建多路复用、同步非阻塞的 I/O 程序。
- 多路复用:通过 Selector 机制,单个线程可以同时监控多个 Channel 上的 I/O 事件(如连接就绪、读写就绪),从而实现一个线程处理多个客户端连接。
- 同步非阻塞:应用程序发起 I/O 操作后,会立即返回,不会阻塞当前线程。当数据准备就绪时,应用程序会收到通知,然后进行后续处理。
- 面向缓冲区:数据读写操作都通过 Buffer 进行,提高了数据处理效率。
- 更接近底层:NIO 提供了更接近操作系统底层的高性能数据操作方式。
AIO (Asynchronous I/O)
AIO,即 Asynchronous I/O,是 Java 7 之后引入的 I/O 模型,通常被称为异步 I/O。它是 NIO 的升级版本,提供了真正的异步非阻塞 I/O 操作方式。
- 异步非阻塞:应用程序发起 I/O 操作后,会立即返回,不需要等待数据准备就绪或操作完成。当 I/O 操作在操作系统层面完成后,会通过回调机制或事件通知应用程序。
- 事件和回调:AIO 基于事件和回调机制实现,应用程序不再需要主动轮询 I/O 状态,而是被动接收操作完成的通知。
同步与异步
同步 (Synchronous):
- 当一个任务的完成需要依赖另一个任务时,只有等待被依赖的任务完成后,依赖的任务才能继续执行并被视为完成。
- 这是一种可靠的任务序列,通常意味着操作结果的一致性(要么都成功,要么都失败)。
- 比喻:打电话,A 等待 B 接听并回应,A 才能继续沟通。
异步 (Asynchronous):
- 应用程序发出请求后,不需要等待被依赖的任务完成,而是立即执行自己的后续操作。
- 被依赖的任务在后台独立执行,并在完成后通过通知或回调机制告知发起者。
- 这种序列不可靠,发起者无法立即确定被依赖任务的最终完成状态。
- 比喻:发短信,A 发送短信后可立即进行其他操作,无需等待 B 回复。
阻塞与非阻塞
定义
阻塞 (Blocking):
- 当一个慢速操作(如 I/O 操作)正在执行时,CPU 会暂停当前线程的执行,等待该操作完成。
- 在此期间,CPU 资源被浪费,无法执行其他任务。
非阻塞 (Non-Blocking):
- 当一个慢速操作正在执行时,CPU 不会暂停当前线程,而是立即返回,并可以去执行其他任务。
- 当慢速操作完成后,CPU 会收到通知,然后回来处理后续逻辑。
- 优点:提高了 CPU 的利用率。
- 缺点:可能增加系统上下文切换的开销。在评估非阻塞方式的收益时,需要权衡 CPU 利用率的提升与切换成本的增加。
关系辨析
同步与阻塞/非阻塞没有必然关系:
- 同步不一定阻塞:例如,NIO 中的 Selector 就是同步的(应用程序需要主动调用
select()方法),但它是非阻塞的(select()方法可以设置超时,或者在没有事件时立即返回)。 - 异步不一定非阻塞:如果一个异步操作的实现机制在内部仍然依赖于阻塞调用,那么它对外表现为异步,但内部仍可能存在阻塞。然而,通常意义上的异步 I/O (如 AIO) 是非阻塞的。
总结来说,阻塞与非阻塞关注的是程序在等待 I/O 完成时是否暂停当前线程(CPU 是否等待),而同步与异步关注的是程序在发起 I/O 操作后,是否需要等待操作结果才能继续执行后续逻辑(控制流是否等待)。