java nio非阻塞socket通信核心是serversocketchannel、socketchannel配合selector事件轮询,需显式configureblocking(false),read/write返回值须检查,selector通过内核通知高效管理多连接,数据收发依赖bytebuffer手动管理状态。

Java NIO 实现非阻塞 Socket 通信,核心在于用 ServerSocketChannel 和 SocketChannel 替代传统阻塞式 Socket,配合 Selector 进行事件轮询,避免线程在 accept、read、write 上挂起。
设置通道为非阻塞模式
非阻塞的前提是显式调用 configureBlocking(false)。否则即使用了 NIO 组件,通道仍默认阻塞。
-
ServerSocketChannel:绑定端口后必须设为非阻塞,否则
accept()会一直等待连接 -
SocketChannel:客户端连接成功或服务端 accept 返回后,也要立即设为非阻塞,否则
read()或write()可能阻塞 - 注意:非阻塞通道的 read/write 方法返回值需检查——返回 0 表示暂无数据或写入缓冲区已满;返回 -1 表示对端已关闭连接
用 Selector 管理多个连接
Selector 是实现单线程处理多连接的关键。它不主动轮询,而是通过内核就绪通知(如 epoll/kqueue)高效获知哪些 Channel 有事件可处理。
- 创建 Selector:
Selector.open() - 注册 Channel:调用
channel.register(selector, ops, attachment),其中ops是关注的事件,如SelectionKey.OP_ACCEPT(服务端)、OP_READ(客户端/服务端接收数据)、OP_WRITE(一般用于流控后恢复写) - 阻塞式 select():调用
selector.select()会阻塞,直到至少一个 Channel 就绪;也可用selectNow()非阻塞轮询(但不推荐高频调用) - 遍历就绪集合:
selector.selectedKeys()获取就绪的 SelectionKey,逐个处理其关联的 Channel 和事件类型
典型服务端事件循环结构
一个健壮的 NIO 服务端主循环通常包含三类事件处理逻辑:
-
OP_ACCEPT:调用
serverChannel.accept()得到新SocketChannel,设为非阻塞,并注册OP_READ到同一 Selector -
OP_READ:分配 ByteBuffer,调用
channel.read(buffer);读完后 flip 并解析数据;若 read 返回 -1,说明客户端断开,应取消 key 并关闭 channel - OP_WRITE:仅在写缓冲区满、write 返回 0 后才注册该事件;写完记得取消 OP_WRITE,否则会持续触发(write 本身不阻塞,但频繁空转浪费 CPU)
缓冲区与数据收发细节
NIO 的数据操作完全基于 Buffer,且需手动管理 position/capacity/limit,这是与 BIO 的关键差异。
- 接收数据时,先
buffer.clear()(重置 position=0, limit=capacity),再channel.read(buffer),然后buffer.flip()(limit=position, position=0)准备读取有效字节 - 发送数据前,确保 buffer 处于读模式(flip 后),调用
channel.write(buffer);若未一次写完(返回值小于 buffer.remaining()),需保留 buffer 并注册 OP_WRITE,等下次就绪再续写 - 建议使用 direct buffer(
ByteBuffer.allocateDirect())提升网络 I/O 性能,尤其在高吞吐场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











