java nio通过selector实现多路复用,需使用configureblocking(false)的selectablechannel注册,严格遵循注册→select()→处理→remove()四步闭环,正确区分op_accept/op_read/op_write事件,并注意资源复用与异常清理。

Java NIO 使用 Selector 实现多路复用,核心是让一个线程高效监听多个非阻塞通道的就绪事件,而不是靠轮询或为每个连接开线程。
必须用非阻塞通道注册
只有继承 SelectableChannel 且调用 configureBlocking(false) 的通道才能注册到 Selector。常见可注册通道包括:
- ServerSocketChannel(只注册 OP_ACCEPT)
- SocketChannel(注册 OP_READ,按需临时加 OP_WRITE)
- DatagramChannel
FileChannel 不可注册——它不是 SelectableChannel 子类。注册前漏掉 configureBlocking(false),会直接抛 IllegalBlockingModeException,这是最常见错误。
严格遵循注册 → select() → 处理 → remove() 四步闭环
Selector 工作不是自动的,必须手动完成以下流程:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 注册:用
channel.register(selector, ops, attachment),ops是位掩码(如OP_READ | OP_WRITE) - 等待:调
selector.select()(阻塞),或select(100)(超时 100ms) - 处理:遍历
selectedKeys(),用 Iterator 安全访问每个SelectionKey - 清理:每次处理完一个 key 后,必须调
iterator.remove();否则下次select()还会返回它,导致重复处理
注意:不能在遍历时直接调 selectedKeys().remove(key) 或 key.cancel(),会触发 ConcurrentModificationException。
事件注册要分清角色和时机
不同通道关注的事件类型不同,混用会导致逻辑失效:
- ServerSocketChannel 启动后,只注册 OP_ACCEPT;它不支持
OP_READ,强行注册会使 key 失效 - accept() 得到的 SocketChannel,先设为非阻塞,再注册 OP_READ
- OP_WRITE 要慎用:TCP 发送缓冲区未满时它几乎总是就绪,容易引发 CPU 空转;只应在 write 返回 -1(写半包)后显式注册,写完立即取消
处理数万连接时的关键优化点
高并发下稳定运行,光逻辑正确不够,还得注意资源管理:
- 每个连接配独立
ByteBuffer容易耗尽 DirectMemory;建议用对象池(如 Netty 的 PooledByteBufAllocator)复用 buffer - 异常关闭或 I/O 错误时,应调
key.cancel()并显式channel.close(),防止连接泄漏 - 用
attachment携带上下文(如解析状态、会话 ID、ByteBuffer 引用),避免额外 map 查找 - 多线程操作 Selector 时,用
selector.wakeup()通知阻塞中的select()提前返回,保证事件及时响应
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










