Java中Selector通过操作系统内核(如Linux的epoll)实现I/O多路复用,单线程轮询成千上万Channel就绪状态;需非阻塞模式注册、指定事件类型、select后遍历处理selectedKeys并手动remove,形成闭环事件驱动模型。

Java 中 Selector 实现多路复用,本质是把“监听多个连接”的活交给操作系统内核,自己只用一个线程轮询结果,而不是为每个连接分配一个线程。
Selector 依赖操作系统底层机制
Java 的 Selector 并不是纯 Java 实现的轮询器,它在 Linux 上底层调用的是 epoll,在 macOS/BSD 上是 kqueue,Windows 上模拟为 select。这些系统调用允许单个线程监控成千上万个文件描述符(对应 Java 中的 Channel)的状态变化。
- 注册 Channel 时,Selector 会通过系统调用把该 Channel 对应的 fd 加入内核事件表
- 调用
select()或selectNow()时,线程实际是阻塞在内核的 epoll_wait 等系统调用上 - 当某个 socket 缓冲区有数据到达、连接建立完成或可写时,内核主动通知 Selector,返回就绪的 Channel 列表
关键操作流程必须闭环
一个可用的 Selector 循环不能只注册和 select,必须保证事件处理与清理同步,否则会漏事件或重复处理。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- Channel 必须设为非阻塞模式(
configureBlocking(false)),否则注册会失败 - 注册时指定事件类型:如
OP_ACCEPT(服务端接收新连接)、OP_READ(有数据可读)、OP_WRITE(可发送数据) -
select()返回后,要遍历selectedKeys()集合,逐个判断isAcceptable()、isReadable()等 - 每处理完一个
SelectionKey,必须手动调用iterator.remove()—— 否则下次 select 仍会返回它
事件驱动模型替代线程绑定
传统 BIO 是“连接即线程”,而 Selector 模式下,线程不和连接绑定,只和“事件”绑定:
立即学习“Java免费学习笔记(深入)”;
- 一个客户端连接进来,触发
OP_ACCEPT,主线程 accept 得到 SocketChannel,再把它注册进 Selector 并关注OP_READ - 该连接后续发来数据,触发
OP_READ,同一主线程从缓冲区读取,处理业务逻辑 - 若需要回包且缓冲区满,可临时关注
OP_WRITE,等可写时再发送,避免阻塞
整个过程始终只用一个线程管理数万连接,真正复用的是“等待 I/O 就绪”这个能力,不是通道本身。

















