java中一个selector可注册多个非阻塞channel,需调用channel.register(selector, ops)并指定事件;每个channel仅能注册一次,重复调用会更新兴趣集而非新建key。

Java 中一个 Selector 可以注册多个 Channel,关键在于每个 Channel 必须配置为非阻塞模式,并通过 channel.register(selector, ops) 方法完成注册。同一个 Selector 实例可管理成百上千个通道,这是 NIO 实现高并发 I/O 的核心机制。
Channel 必须是非阻塞模式
只有非阻塞的 Channel(如 SocketChannel、ServerSocketChannel、DatagramChannel)才能注册到 Selector。阻塞通道调用 register() 会直接抛出 IllegalBlockingModeException。
设置方式示例:
SocketChannel ch = SocketChannel.open(); ch.configureBlocking(false); // 必须这一步
使用 register() 方法注册多个 Channel
每个 Channel 调用一次 register() 即可加入该 Selector 的监听集合。注册时需指定感兴趣的事件(SelectionKey.OP_READ、OP_WRITE、OP_ACCEPT、OP_CONNECT),也可用位或组合多个事件。
常见注册方式:
-
serverChannel.register(selector, SelectionKey.OP_ACCEPT)—— 服务端监听新连接 -
clientChannel.register(selector, SelectionKey.OP_READ)—— 客户端监听读就绪 -
clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE)—— 同时监听读写
注册后通过 SelectionKey 关联 Channel 和事件
每次成功注册都会返回一个 SelectionKey,它持有对 Channel、Selector、事件集和附件(attachment)的引用。你可以把业务对象作为附件绑定过去,便于后续处理:
SelectionKey key = channel.register(selector, ops, myHandler);
在 selector.select() 返回后,遍历 selectedKeys() 集合,就能拿到所有就绪的 SelectionKey,再通过 key.channel() 获取对应 Channel,安全地执行 I/O 操作。
注意:避免重复注册同一个 Channel 到同一 Selector
同一个 Channel 对同一个 Selector 只能注册一次。再次调用 register() 不会新建 SelectionKey,而是更新原 SelectionKey 的兴趣集(interest set)和附件。若需修改监听事件,应通过 key.interestOps(newOps) 显式变更,更清晰可控。
判断是否已注册的方法:
-
channel.keyFor(selector) != null—— 返回对应 key,null 表示未注册 - 不建议靠捕获异常来判断,应主动检查
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











