跳转至

IO 模型有哪些?谈谈你理解的 NIO,它和 BIO、AIO 的区别,Reactor 模型?

一、五种 IO 模型

Unix 提出的五种:

  1. 阻塞 IO(BIO):recvfrom 一直等数据。
  2. 非阻塞 IO(NIO):recvfrom 立即返回 EWOULDBLOCK,循环问。
  3. IO 多路复用:select/poll/epoll 同时等多个 fd。
  4. 信号驱动 IO:内核通知可以 IO。
  5. 异步 IO(AIO):内核把数据拷贝完再通知。

二、BIO vs NIO vs AIO

BIO NIO AIO
模式 同步阻塞 同步非阻塞 异步非阻塞
核心 Stream Channel + Buffer + Selector Future/Callback
适用 连接少 连接多 连接多、操作重

BIO

一个连接一个线程,连接不做事也占线程。

NIO(Java NIO)

  • 三要素:Channel、Buffer、Selector。
  • 一个线程通过 Selector 管理多个 Channel。
  • 同步非阻塞:线程发起 read,数据没准备好就返回,线程去做别的事。

AIO

  • 真正异步:发起 read,内核准备好数据并拷贝到用户缓冲区后,回调通知。
  • Linux 上 AIO 实现不完善,Windows 用得好。

三、Reactor 模型

NIO 的经典设计模式:

单 Reactor 单线程

Reactor -> Accept -> Read -> Decode -> Process -> Encode

一个线程跑所有事件。简单,但 CPU 密集场景是瓶颈。

单 Reactor 多线程

读解码在主线程,业务处理丢到线程池。

主从 Reactor 多线程(Netty)

  • 主 Reactor:只 accept 连接。
  • 从 Reactor:处理已建立连接的读写。
  • 业务线程池:处理业务。

Netty 就是这种模型。

四、Java NIO 三要素

Channel

双向通道,可读可写。常见:SocketChannel、ServerSocketChannel、FileChannel。

Buffer

数据容器,有 position/limit/capacity 三个指针。

Selector

一个线程监听多个 Channel 的事件(connect/read/write/accept)。

五、零拷贝

NIO 的 FileChannel.transferTo() 用 sendfile 系统调用,数据直接从文件到 Socket,不经过用户态。

高频追问

  • 为什么 FileChannel 不能非阻塞?文件 IO 没有"等待连接"的概念。
  • epoll vs select:epoll 没有 fd 上限,回调机制,适合大规模连接。