Java NIO异常需分类处理:ClosedChannelException检查提前关闭,AsynchronousCloseException确保单线程管理channel,CancelledKeyException轮询前校验isValid(),IOException触发重建;ByteBuffer须正确flip/compact;连接失败退出流程,OP_CONNECT未完成需继续监听,read返回-1正常关闭、抛IOException则重连;select须设超时并清理keys,空闲超时主动断连。

分类捕获关键IO异常
Java NIO 的异常大多继承自 IOException,但不同子类代表完全不同的故障原因,必须分开处理:
- ClosedChannelException:通道已被关闭,常见于多线程误用或提前释放资源。应检查是否在 write/read 前已调用 close(),或未加锁共享 channel
- AsynchronousCloseException:另一线程调用了 channel.close(),当前操作被强制中断。需确保 channel 生命周期由单一责任方管理
-
CancelledKeyException:SelectionKey 已失效(如 channel 关闭后 key 未取消),应在每次轮询前用
key.isValid()校验 - IOException(无具体子类):底层连接重置、网络中断等通用错误,适合触发链路重建或心跳恢复逻辑
防止 ByteBuffer 状态错乱引发异常
多数 NIO 数据异常(如读不到数据、写入失败、空包)根源不在网络,而在 ByteBuffer 模式切换失误:
- 写入数据后必须调用
flip()才能正确 write 到 channel;否则 position > limit,write 返回 0 - 读取部分数据后若需继续写入(如半包场景),不能用
clear()(会丢弃未读字节),而要用compact()将剩余数据移到开头 - 每次 read() 后检查返回值:-1 表示对端已关闭连接,0 表示本次无新数据(非错误),需结合业务逻辑判断是否继续等待
应对连接级与通信级异常的策略差异
NIO 中异常要按作用域分层响应:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 连接建立失败(如 connect() 抛异常):属于初始化问题,应记录错误并退出该连接流程,不进入 selector 轮询
- OP_CONNECT 事件中 finishConnect() 返回 false:说明连接仍在进行中,需继续监听 OP_CONNECT,不可直接注册 OP_READ
- OP_READ 时 read() 返回 -1:对端正常关闭,应 clean up key、关闭 channel、移除相关缓存
- OP_READ 时 read() 抛 IOException:链路异常中断,需关闭 channel 并触发重连或告警
用 Selector 和超时机制规避阻塞与假死
NIO 不等于“不阻塞”,selector.select() 默认会无限等待,必须主动控制:
立即学习“Java免费学习笔记(深入)”;
- 始终使用
select(timeout)(如 1000ms),避免线程挂起导致整个 reactor 停摆 - 在每次 select() 返回后,遍历 selectedKeys 时用
Iterator.remove()及时清理,防止重复处理或 ConcurrentModificationException - 对长时间无响应的 channel,可配合 IdleStateHandler(Netty)或自定义空闲计时器,在读/写空闲超时后主动断开,防资源滞留

















