一、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或事件驱动epollAIO回调OS 异步通知二、NIO 多路复用的核心组件2.1 三大核心概念┌─────────────────────────────────────────────────┐ │ Java NIO 多路复用模型 │ ├─────────────────────────────────────────────────┤ │ │ │ Selector多路复用器 │ │ ├─ Channel 1FileChannel │ │ ├─ Channel 2SocketChannel │ │ ├─ Channel 3ServerSocketChannel │ │ └─ 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 SetSelectionKey selectedKeys selector.selectedKeys(); IteratorSelectionKey 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 / epollsetInterval/Scheduled阻塞阻塞内核select()阻塞HTTP 阻塞性能极高单线程处理万级连接一般每次都是完整 HTTP 请求资源消耗极小复用连接大每次新建连接实时性毫秒级秒级取决于间隔项目Netty / Spring Cloud Gateway5 秒轮询报表四、NIO 轮询的 3 大底层实现重要4.1 select / poll / epoll 对比维度selectpollepollLinux时间复杂度O(n)O(n)O(1)文件描述符限制1024无限制无限制内核实现轮询轮询事件驱动回调跨平台✅✅❌仅 Linux性能差差⚠️⚠️⚠️ 极好老哥项目老项目老项目Netty / Spring Cloud Gateway4.2select 轮询机制最差但跨平台// select 实现内核轮询所有 fd int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);报表定时任务轮询——应用层 select 类似的 setInterval。4.3epoll 事件驱动机制最好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.5Channel 双向比 Stream 强维度StreamBIOChannelNIO读写单向双向缓冲❌必须配合 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 是回调