Java NIO中Selector异常需在创建、注册、轮询和通道操作四环节防御处理:select()须try-catch IOException;register前确保通道非阻塞且未关闭;遍历selectedKeys时先校验key.isValid()和channel.isOpen();OP_WRITE注册后须及时注销,写操作异常应关闭通道并取消key。

Java NIO 中的 Selector 本身不会主动“抛出异常”供上层直接 catch,它是一个事件轮询器,正常运行时是静默的。真正可能抛出异常的环节集中在**创建、注册、轮询和通道操作**这几个关键步骤,需要在对应位置做防御性处理。
selector.select() 调用时的异常捕获
这是最常遇到异常的地方。select() 方法声明抛出 IOException,主要由底层系统调用(如 epoll_wait)失败触发,常见原因包括:JVM 被信号中断、文件描述符耗尽、内核资源异常等。
- 必须用
try-catch包裹整个select()调用,不能只包循环体内部 - 捕获
IOException后,通常应记录日志并考虑是否退出或重建 Selector - 不要忽略或静默吞掉该异常,否则轮询会中断且无提示
通道注册阶段的异常处理
调用 channel.register(selector, ops) 前,通道必须已设为非阻塞模式;否则会抛出 IllegalBlockingModeException。此外,已关闭的通道注册会触发 ClosedChannelException。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 确保
configureBlocking(false)在register()之前执行且成功 - 注册前检查通道状态:
if (!channel.isOpen()) { /* 跳过或清理 */ } - 对
register()调用本身也建议包裹try-catch,尤其在动态注册场景中
selectedKeys 遍历时的 Key 状态校验
selectedKeys() 返回的集合中,某些 SelectionKey 可能已被取消(key.isValid() == false),或其关联通道已关闭。若直接调用 key.channel() 或 key.interestOps() 可能引发 CancelledKeyException 或 ClosedChannelException。
立即学习“Java免费学习笔记(深入)”;
- 每次从
Iterator取出key后,第一件事就是判断if (!key.isValid()) { continue; } - 处理前再检查通道是否仍打开:
if (!key.channel().isOpen()) { key.cancel(); continue; } - 避免在未校验状态下直接调用
key.attachment()或 I/O 操作方法
OP_WRITE 注册与注销中的典型异常点
OP_WRITE 事件容易被误用:一旦注册,只要通道可写就会持续就绪,若不及时注销,会导致空轮询甚至 write() 抛出 IOException(如对端关闭连接)。
- 仅在写缓冲区满、写操作返回 0 或抛出
IOException时才注册OP_WRITE - 完成一次写入后,必须立即调用
key.interestOps(SelectionKey.OP_READ)注销写事件 - 写操作中捕获
IOException(如 Connection reset、Broken pipe),应关闭通道并取消 key

















