Java用单个Selector监听多端口的核心是每个端口对应独立ServerSocketChannel并注册到同一Selector,通过非阻塞模式与事件轮询统一管理;需正确配置通道、设置attachment标识端口、规范处理selectedKeys及避免阻塞操作。

Java 使用 Selector 监听多个不同端口,核心在于:**每个端口对应一个独立的 ServerSocketChannel,且都注册到同一个 Selector 上,通过非阻塞模式和事件轮询实现统一管理。**
1. 创建并配置 Selector 和多个 ServerSocketChannel
先获取 Selector 实例,再为每个要监听的端口创建一个 ServerSocketChannel,设置为非阻塞,并绑定对应端口:
- 调用
Selector.open()获取选择器 - 对每个端口:
ServerSocketChannel.open()channel.configureBlocking(false)channel.bind(new InetSocketAddress(port))channel.register(selector, SelectionKey.OP_ACCEPT)
注意:不能用同一个 ServerSocketChannel 绑定多个端口;每个端口必须是独立通道。
2. 在一个线程中循环 select 并分发事件
用单个线程调用 selector.select() 阻塞等待就绪事件,再遍历 selectedKeys() 处理不同端口的连接请求:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 检查
key.isAcceptable()→ 调用对应 channel 的accept()获取SocketChannel,设为非阻塞后注册OP_READ - 检查
key.isReadable()→ 从对应SocketChannel读取数据(需自行关联端口或业务上下文) - 建议为每个
SelectionKey设置attachment(如端口号、处理器对象),方便后续识别来源
3. 区分不同端口的业务逻辑
由于多个端口共用一个 selector,必须在处理时明确知道当前事件来自哪个端口:
- 注册时使用
channel.register(selector, OP_ACCEPT, portNumber),把端口号作为 attachment - 处理
OP_ACCEPT时,从 key 取出 attachment 得知是哪个端口有新连接 - 接受连接后,新
SocketChannel的 key 也可附带相同端口信息,便于后续读写时路由到对应协议解析器(如 HTTP / 自定义二进制协议)
4. 注意事项与常见坑
避免因疏忽导致监听失效或线程卡死:
-
select()返回后,必须手动调用Iterator.remove()清除已处理的 key,否则会重复触发 - 所有涉及 I/O 的 channel(包括
SocketChannel)都必须设为configureBlocking(false) - 不要在 selector 线程里执行耗时操作(如数据库查询、复杂计算),应交由业务线程池处理
- 关闭资源时,按顺序关闭 channel → key.cancel() → selector.close()
不复杂但容易忽略。关键就是“一 selector + 多 channel + 合理 attachment + 规范事件循环”。

















