Java NIO通过Selector实现单线程多路复用,用一个线程轮询成千上万个非阻塞Channel,仅在OP_ACCEPT、OP_READ等事件就绪时处理,避免线程资源浪费,底层封装epoll/kqueue等系统调用,配合Buffer实现高效数据流转。

Java NIO 通过“单线程多路复用”机制,从根本上绕开了高并发连接带来的线程资源瓶颈。它不靠堆线程来撑连接数,而是让一个线程持续轮询成千上万个连接的状态,只在真正有数据可读、可写或新连接到达时才去处理——空闲连接不占CPU、不耗栈内存。
用 Selector 实现事件驱动的连接管理
Selector 是 NIO 应对高并发的核心。它把操作系统底层的多路复用能力(Linux 的 epoll、macOS 的 kqueue)封装成统一 API,允许一个线程同时注册并监控大量 Channel 的 I/O 事件:
- ServerSocketChannel 注册 OP_ACCEPT,监听新连接接入
- SocketChannel 注册 OP_READ(必要时加 OP_WRITE),只在数据就绪时触发回调
- select() 调用会阻塞直到至少一个通道就绪,避免空转消耗 CPU
- 每次处理完 selectedKeys 后必须手动 remove(),否则该 key 会重复出现在下次集合中
Buffer + Channel 构建非阻塞数据流转
传统 BIO 每次 read() 都可能阻塞线程;NIO 中的 Channel 配合 Buffer,把数据操作变成“批量+状态可控”的过程:
- Channel.configureBlocking(false) 启用非阻塞模式,read() 立即返回:有数据则读入 Buffer,无数据则返回 0 或 -1,线程不会挂起
- ByteBuffer.flip() 切换读写模式,clear() 或 compact() 复用缓冲区,减少内存分配压力
- 小消息可复用固定大小 Buffer(如 4KB),大消息配合 direct buffer 或分片处理,避免频繁拷贝
规避常见陷阱,保障稳定吞吐
高性能不等于高可用,实际部署中几个关键点直接影响能否稳住万级连接:
立即学习“Java免费学习笔记(深入)”;
- 不要在 Selector 线程里做耗时业务逻辑(如数据库查询、JSON 解析),应交由业务线程池异步处理,防止阻塞事件循环
- OP_WRITE 需谨慎注册:TCP 缓冲区满时 write() 会失败,此时才需注册 OP_WRITE;写完后及时取消,否则会持续触发无效通知
- 连接异常(如客户端断连)必须主动 close() 对应 Channel 并取消 SelectionKey,否则泄漏的 key 会拖慢 select 性能
- 合理设置 SO_BACKLOG(服务端 accept 队列长度)和 TCP_NODELAY,减少握手与小包延迟
这套机制不是“更省力”,而是“更聪明地用力”。当连接数从几百涨到几万,线程数仍能控制在个位数或十位数,CPU 和内存开销几乎不变——这才是 NIO 在即时通讯、物联网网关、API 网关等场景成为事实标准的原因。



















