3 大 I/O 模型BIO / NIO / AIO

一、3 大 I/O 模型真实的关系是什么?

复制代码
3 大 I/O 模型
├─ BIO(同步阻塞)
│   └─ 通知方式:❌ 无通知(线程挂起等)
│
├─ NIO(同步非阻塞)= 多路复用
│   ├─ select/poll:⚠️ 轮询(O(n))
│   └─ epoll:⚠️ 事件驱动(O(1))
│
└─ AIO(异步非阻塞)
    └─ ✅ 回调(OS 通知)

真相是

  • 3 大 I/O 模型 = BIO / NIO / AIO (按同步性 + 阻塞性分类)
  • "轮询 / 事件驱动 / 回调" 是 3 种通知方式不是 3 大 I/O 模型
  • 每种 I/O 模型用不同的通知方式
    • BIO无通知线程挂起
    • NIO轮询select/poll )或事件驱动epoll
    • AIO回调OS 异步通知

二、NIO 多路复用的核心组件

2.1 三大核心概念
复制代码
┌─────────────────────────────────────────────────┐
│  Java NIO 多路复用模型                            │
├─────────────────────────────────────────────────┤
│                                                  │
│  Selector(多路复用器)                           │
│  ├─ Channel 1(FileChannel)                    │
│  ├─ Channel 2(SocketChannel)                  │
│  ├─ Channel 3(ServerSocketChannel)            │
│  └─ Channel N(...)                            │
│                                                  │
│  ⚠️ Selector 内部"轮询"这些 Channel             │
│     哪个有事件就处理哪个                         │
│                                                  │
└─────────────────────────────────────────────────┘
组件 作用 比喻
Channel 数据通道(双向) 水管
Buffer 数据缓冲区 水桶
Selector 多路复用器 总开关(轮询所有水管)
2.2 工作流程(核心 4 步
复制代码
// 1. 创建 Selector
Selector selector = Selector.open();

// 2. 把 Channel 注册到 Selector
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);  // ⚠️ 非阻塞
serverChannel.register(selector, SelectionKey.OP_ACCEPT);

// 3. 轮询(**核心步骤**)
while (true) {
    // ⚠️ selector.select() 内部轮询所有 Channel
    int readyChannels = selector.select();  // 阻塞,直到有 Channel 就绪
    
    if (readyChannels == 0) continue;
    
    // 4. 处理就绪的 Channel
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectedKeys.iterator();
    
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        
        if (key.isAcceptable()) {
            // 处理新连接
            SocketChannel clientChannel = serverChannel.accept();
            clientChannel.configureBlocking(false);
            clientChannel.register(selector, SelectionKey.OP_READ);
        }
        
        if (key.isReadable()) {
            // 处理读事件
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int bytesRead = channel.read(buffer);
            // ... 处理业务逻辑
        }
        
        iter.remove();
    }
}

三、NIO 轮询 vs 软件系统轮询核心对比

维度 NIO 多路复用轮询 软件系统轮询
轮询对象 OS 内核的 Channel 集合 服务器 / 数据库
轮询位置 OS 内核(零拷贝) 应用层(用户态)
轮询方式 select / poll / epoll setInterval / @Scheduled
阻塞 阻塞内核select() 阻塞) HTTP 阻塞
性能 极高单线程处理万级连接 一般每次都是完整 HTTP 请求
资源消耗 极小复用连接 每次新建连接
实时性 毫秒级 秒级(取决于间隔)
项目 Netty / Spring Cloud Gateway 5 秒轮询报表

四、NIO 轮询的 3 大底层实现重要

4.1 select / poll / epoll 对比
维度 select poll epollLinux
时间复杂度 O(n) O(n) O(1)
文件描述符限制 1024 无限制 无限制
内核实现 轮询 轮询 事件驱动回调
跨平台 ❌(仅 Linux
性能 ⚠️⚠️⚠️ 极好
老哥项目 老项目 老项目 Netty / Spring Cloud Gateway
4.2 select 轮询机制最差,但跨平台
复制代码
// select 实现:内核轮询所有 fd
int select(int nfds, fd_set *readfds, fd_set *writefds, 
           fd_set *exceptfds, struct timeval *timeout);

报表定时任务轮询 ------应用层 select 类似的 setInterval

4.3 epoll 事件驱动机制最好,Linux)
复制代码
// epoll 实现:内核用红黑树 + 事件回调
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

Spring Cloud GatewayWebFlux 异步非阻塞 )------底层用 epoll

五、NIO 多路复用的 5 大优势

5.1 单线程处理万级连接

Spring Cloud Gateway 实战Netty 底层):

复制代码
1 个 Netty 线程 → 处理 1w+ 并发连接
vs
1 个 Tomcat 线程 → 处理 200 并发连接
5.2 零拷贝mmap / sendfile
复制代码
传统 I/O:磁盘 → 内核缓冲 → 用户缓冲 → Socket 缓冲 → 网卡
NIO 零拷贝:磁盘 → 内核缓冲 → 网卡(少 2 次拷贝)
5.3 事件驱动不轮询
复制代码
select/poll:内核**轮询**所有 fd
epoll:内核用**回调**通知(**事件驱动**)
5.4 内存映射mmap
复制代码
// MappedByteBuffer:直接把文件映射到内存
FileChannel channel = FileChannel.open(Paths.get("large-file.log"));
MappedByteBuffer buffer = channel.map(
    FileChannel.MapMode.READ_ONLY, 0, channel.size());
// 读取就像读内存一样快
5.5 Channel 双向比 Stream 强
维度 Stream(BIO) Channel(NIO)
读写 单向 双向
缓冲 必须配合 Buffer
阻塞 非阻塞
多路复用

六、3 大 I/O 模型类比

"BIO = 线程挂起等 (像打电话,对方不接就一直等NIO = 主动轮询 / 事件通知 (像发短信,发了就干别的,等回信再看AIO = OS 回调(像发短信 + 对方主动打电话给你)"

七、记忆口诀

"3 大 I/O 模型:BIO 同步阻塞,NIO 同步非阻塞,AIO 异步非阻塞"

"3 种通知方式:轮询 / 事件驱动 / 回调"不是 3 大 I/O 模型

"BIO = 线程挂起等(不是中断)"

"NIO = 多路复用(select/poll 轮询,epoll 事件驱动)"

"AIO = OS 回调"

"Spring Cloud Gateway / Redis / Kafka 都用 NIO"

八、总结

复制代码
1. 什么是轮询?
   └─ 软件系统层面:客户端反复问服务器(应用层)

2. NIO 多路复用中的轮询?
   └─ OS 层面:NIO 底层 select/poll 是真轮询,epoll 是事件驱动

3. 3 大 I/O 模型?
   └─ BIO / NIO / AIO(按同步性 + 阻塞性分类)
   └─ 3 种通知方式:轮询 / 事件驱动 / 回调(不是 3 大 I/O 模型)

4. BIO 是中断吗?NIO 是事件驱动?AIO 是回调?
   └─ ❌ BIO 不是中断(是线程挂起)
   └─ ⚠️ NIO 不全是事件驱动(select/poll 是轮询,epoll 才是)
   └─ ✅ AIO 是回调
相关推荐
Pluto_CSND1 小时前
Cron表达式使用说明
java
十五喵源码网1 小时前
基于SpringBoot2+vue2的酒店客房管理系统
java·毕业设计·springboot·论文笔记
小小小花儿1 小时前
服务器上修改个人账户权限
linux·服务器
Coisinier1 小时前
RHCE中shell脚本基础(磁盘剩余空间监控,Web 服务状态检查,curl 访问 Web 服务并返回状态)
linux·运维·服务器·前端·nginx·操作系统
swordbob1 小时前
CAP 定理:为什么不能同时实现 C、A、P?
开发语言·后端·spring
疯狂成瘾者1 小时前
Java 常用工具包 java.util
java·开发语言·windows
ywl4708120871 小时前
springSecurity+jwt,简单版demo
java·前端·servlet
SXJR2 小时前
spring boot + langchain4j +milvus实现向量存储
java·spring boot·后端·大模型·milvus·rag·langchain4j
武子康2 小时前
Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC 从 XML 配置到 BeanFactory 反射注入
java·后端·mybatis