主从 Reactor 架构通过 Boss 线程专管 ACCEPT、Worker 线程专管 READ/WRITE 实现多核高效利用;Worker 数量匹配 CPU 核心数,单 Selector 控制 2000–4000 连接,无锁轮询分配连接,业务逻辑须异步化。
核心思路是让每个 cpu 核心“专管一批连接”,而不是让一个 selector 独自扛下所有通道。这靠的不是多开几个 selector,而是用主从 reactor 架构把接入、分发、处理彻底拆开。
主从 Reactor 分工必须明确
单个线程+单个 Selector 无法压满多核,因为 ACCEPT 和 READ/WRITE 混在一起,一卡全卡。正确做法是:
- 启动一个 Boss 线程(main reactor),只注册 ServerSocketChannel,只监听 OP_ACCEPT
- 准备一组 Worker 线程(sub reactor),每个线程持有一个独立 Selector 和事件循环
- Boss 接收到新连接后,立即调用 accept() 得到 SocketChannel,再轮询分配给某个 Worker(比如下标取模)
- 该 SocketChannel 后续所有 OP_READ / OP_WRITE 都由所属 Worker 全权处理,不再跨线程
Selector 实例数量要匹配硬件能力
不是越多越好,关键看 CPU 核心数和连接活跃度:
- Worker 数量通常设为 CPU 逻辑核心数(如 16 核配 16 个),最多不超过核心数 × 2
- 每个 Selector 上注册的 Channel 控制在 2000–4000 个以内;可通过监控 selectedKeys().size() 和 select() 平均耗时判断是否过载
- 若连接多为长连接+低频心跳(如 IoT 场景),可适当放宽单 Selector 容量
- 若为短连接高频交互(如 HTTP API),应倾向更多 Worker,降低单次事件延迟
连接分配必须无状态且低开销
Boss 线程不能依赖共享变量做负载统计,否则会成为热点瓶颈:
- 避免使用 AtomicInteger.incrementAndGet() 做轮询计数——高并发下 CAS 失败率飙升
- 推荐用 ThreadLocalRandom 或预计算下标数组(如 int[] reactors = {0,1,2,3})做无锁轮询
- 分配动作必须在 Boss 线程内完成,不可异步投递;SocketChannel 注册到目标 Worker 的 Selector 必须在对应线程内执行(可用 wakeup() + 队列通知)
实际编码中几个关键细节
光有多个 Selector 不等于负载均衡生效,配套机制缺一不可:
- 所有 Channel 必须 configureBlocking(false),否则无法注册到 Selector
- 每个 Worker 的 Selector 循环里,必须手动调用 keyIterator.remove(),否则已处理 key 会持续堆积
- 业务逻辑不能阻塞 Worker 线程;耗时操作(如 DB 查询、JSON 解析)需提交到业务线程池
- 连接关闭必须由所属 Worker 触发 deregister + close,禁止跨 reactor 操作 Channel

















