2026年7月11日 · 4 分钟阅读

Java IO 模型演进:BIO、NIO 与 AIO 的核心区别

梳理 Java 网络 IO 模型,从 BIO 阻塞通信到 NIO 的 Channel、Buffer、Selector,再到 AIO 的异步模型和适用场景。

Java 网络编程绕不开 IO 模型。BIO、NIO、AIO 不是三个孤立 API,而是网络连接和线程处理方式的演进。

理解它们的关键问题是:当一个连接没有数据可读、没有数据可写时,线程会发生什么?

BIO:阻塞式 IO

BIO 可以理解为 Blocking IO。JDK 1.4 之前,Java 网络通信主要使用 ServerSocketSocket

典型服务端流程:

ServerSocket serverSocket = new ServerSocket(9999);

while (true) {
    Socket socket = serverSocket.accept();
    InputStream in = socket.getInputStream();
    OutputStream out = socket.getOutputStream();
    // read and write
}

问题在于:

  • accept() 会阻塞,直到有客户端连接。
  • read() 会阻塞,直到有数据可读。
  • 一个线程同时只能处理一个连接的阻塞等待。

如果要支持多个客户端,通常要为每个连接创建一个线程。

BIO 的问题

BIO 模型简单,但连接数上来后问题明显。

问题说明
线程数多每个连接一个线程,资源占用高
上下文切换多线程越多,调度成本越高
阻塞浪费大量线程可能只是等待 IO
扩展性差很难支撑大量长连接

BIO 适合连接数较少、逻辑简单、并发压力不高的场景。

NIO:面向缓冲区的非阻塞 IO

NIO 是 New IO,也可以理解为 Non-blocking IO。它和 BIO 的目标一样,都是读写数据,但实现方式完全不同。

NIO 的三大核心组件是:

  • Channel。
  • Buffer。
  • Selector。

BIO 面向流,NIO 面向缓冲区。BIO 一般是单向流,NIO 的 Channel 可以双向读写。

Channel

Channel 是通道,用来连接数据源和目标。

常见 Channel 包括:

  • FileChannel
  • SocketChannel
  • ServerSocketChannel
  • DatagramChannel

Channel 不直接保存数据,读写数据都要经过 Buffer。

Buffer

Buffer 是缓冲区,本质上是一块可读写的内存。

NIO 读写流程通常是:

Channel -> Buffer -> 程序
程序 -> Buffer -> Channel

Buffer 里几个重要指针:

指针含义
capacity容量
position当前读写位置
limit当前可读写边界
mark标记位置

写入 Buffer 后要调用 flip() 切换到读模式;读完后可以 clear()compact() 继续写。

Selector

Selector 是 NIO 支撑高并发网络通信的关键。

一个 Selector 可以监听多个 Channel 的事件,比如:

  • 连接就绪。
  • 读就绪。
  • 写就绪。
  • 接收连接就绪。

这样一个线程就可以管理多个连接。线程不需要阻塞在某个连接上,而是等待“哪些连接已经准备好”。

NIO 网络通信流程

NIO 服务端通常按这个流程工作:

  1. 创建 ServerSocketChannel
  2. 设置为非阻塞模式。
  3. 创建 Selector。
  4. 把 Channel 注册到 Selector,监听 accept 事件。
  5. Selector 轮询就绪事件。
  6. 有连接进来时,创建 SocketChannel
  7. SocketChannel 注册到 Selector,监听 read/write 事件。
  8. 事件就绪后,通过 Buffer 读写数据。

这就是 Reactor 模式的基础。

BIO 和 NIO 对比

对比项BIONIO
IO 方式阻塞非阻塞
数据处理面向流面向缓冲区
线程模型一个连接通常一个线程一个线程可管理多个连接
适用场景连接少、固定连接多、轻量请求
编程复杂度简单较复杂

NIO 的优势不在于单次读写一定更快,而在于更适合大量连接。

AIO:异步 IO

AIO 是 Asynchronous IO。NIO 需要应用线程主动轮询事件,AIO 则更强调异步回调:操作系统完成 IO 后通知应用。

可以简单对比:

模型线程行为
BIO线程发起 IO 后阻塞等待
NIO线程轮询就绪事件,准备好再读写
AIO线程提交 IO 请求,完成后回调通知

AIO 理论上适合连接多、耗时长、需要异步通知的场景,但在 Java 服务端开发中,Netty 这类基于 NIO 的框架更常见。

IO 模型怎么选

可以按连接规模和请求特征选择:

场景建议
少量连接、代码简单BIO
大量连接、轻量请求NIO / Netty
异步文件或特定系统能力AIO
生产级高并发网络服务Netty

工程中很少直接用原生 NIO 写复杂业务,因为 Selector、半包粘包、编解码、线程模型都要自己处理。Netty 正是为了降低这些复杂度。

小结

BIO、NIO、AIO 的区别可以这样记:

  • BIO:一个连接阻塞一个线程,简单但扩展性差。
  • NIO:一个线程管理多个连接,依赖 Channel、Buffer、Selector。
  • AIO:提交异步 IO,完成后回调。

理解 IO 模型后,再看 Netty 的线程模型和 Pipeline,就能明白它为什么建立在 NIO 之上。