SelectionKey.attach()应在通道注册完成、事件触发前立即绑定,如SocketChannel注册OP_READ时attach Session;需校验key.isValid()且attachment非null后强转使用,并在连接关闭前cancel以避免内存泄漏。

Java NIO 中通过 SelectionKey.attach() 绑定自定义业务处理器对象,核心是把通道的运行时状态(如会话、缓冲区、协议解析器)直接挂载到选择键上,实现零查找、无锁、线程安全的状态关联。
什么时候绑定最合理
attachment 应在通道注册完成、事件尚未触发前设置,避免遗漏或覆盖:
- ServerSocketChannel 注册 OP_ACCEPT 后,无需 attach(一般不存业务状态)
- 新 accept 的 SocketChannel 注册 OP_READ 时,立即调用
key.attach(new Session(...)) - 不能在每次 OP_READ 或 OP_WRITE 循环中重复 attach,否则旧对象被丢弃,可能引发内存泄漏或逻辑错乱
怎么构造和绑定业务处理器
建议封装一个轻量、可复用的上下文类,例如 Session,内聚连接相关资源:
- 包含
SocketChannel引用、远程地址、读写ByteBuffer、用户 ID、心跳时间戳等 - 避免在 Session 中持有未管理的外部资源(如未关闭的流、线程池引用)
- 绑定示例:
key.attach(new Session(client, ByteBuffer.allocateDirect(8192)));
事件处理时如何安全取回并使用
在 selector 轮询到就绪 key 后,必须先校验有效性,再强转 attachment:
立即学习“Java免费学习笔记(深入)”;
- 始终检查
if (key.isValid() && key.attachment() != null) - 强转时推荐加 try-catch 或使用泛型工具类封装,防止
ClassCastException - 典型用法:
Session session = (Session) key.attachment(); session.buffer.clear(); channel.read(session.buffer);
配套注意事项不能漏
attachment 是生命周期与 SelectionKey 强绑定的“挂载点”,需配合整体键管理:
- 客户端断连或异常关闭时,应在清理 channel 前主动调用
key.cancel(),attachment 会被自动丢弃 - 若需提前更新上下文(如用户登录后补全身份信息),可再次 attach 新对象,旧对象由 GC 回收
- 不要用 attachment 存储全局单例或共享配置,它只服务于当前通道实例


















