java nio服务端监听核心是“非阻塞+selector多路复用”,通过serversocketchannel.open()、bind()、configureblocking(false)创建配置通道,注册op_accept到selector,在select循环中处理accept事件并为新socketchannel注册op_read,同时注意异常关闭与资源清理。

Java NIO 中处理 ServerSocketChannel 服务端监听,核心是“非阻塞 + Selector 多路复用”,不是靠循环 accept 等待连接,而是让通道注册到选择器后,由系统内核通知“有新连接来了”。整个过程不卡主线程,一个线程就能扛住成千上万并发连接。
创建并配置 ServerSocketChannel
先打开通道、绑定端口、设为非阻塞——这三步缺一不可:
- 调用
ServerSocketChannel.open()获取实例 - 用
socket().bind(new InetSocketAddress(port))绑定本地地址;可传backlog参数控制连接等待队列长度(默认系统值,通常 50) - 必须立即执行
configureBlocking(false),否则无法注册到 Selector,会抛异常
注册 OP_ACCEPT 到 Selector
Selector 是事件调度中心,服务端只关心“谁来连我”这件事:
- 先调用
Selector.open()创建选择器 - 把配置好的
ServerSocketChannel注册进去:serverChannel.register(selector, SelectionKey.OP_ACCEPT) - 注意:此时注册的是“监听连接”的兴趣事件,不是读写;它不会触发 read 或 write,只在有新 TCP 握手完成时就绪
在事件循环中处理新连接
主线程进入 select 循环,等内核通知连接就绪:
-
selector.select()阻塞直到至少一个通道就绪(高效,底层调用 epoll/kqueue) - 遍历
selector.selectedKeys(),对每个SelectionKey判断key.isAcceptable() - 如果是,调用
serverChannel.accept()获取新的SocketChannel(一定不为 null,因为已就绪) - 立刻对这个新
SocketChannel执行configureBlocking(false),再注册OP_READ(或后续加OP_WRITE)到同一个 Selector - 处理完记得调用
key.remove(),避免下次循环重复处理
异常与资源清理要点
真实场景中必须主动兜底,不能依赖 GC:
- 若
accept()抛出IOException(如客户端 RST 中断握手),应关闭对应 key 和 channel - 新
SocketChannel注册失败时,需显式close()防止句柄泄漏 - 可利用
key.attachment()存储关联的ByteBuffer或会话对象,避免反复分配 - 服务关闭时,按顺序调用
serverChannel.close()→selector.close()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











