scatter 和 gather 是 java nio 中专为结构化网络协议设计的高效 i/o 机制,特指 channel.read(bytebuffer[]) 和 channel.write(bytebuffer[]) 接口行为,用于协议头解析与响应拼装,需严格满足 buffer 类型一致、顺序填充/写出及非阻塞通道等约束。

Scatter 和 Gather 是 Java NIO 中专为结构化网络协议设计的高效 I/O 机制,不是泛指“批量读写”,而是特指 channel.read(ByteBuffer[]) 和 channel.write(ByteBuffer[]) 这两个接口行为。在协议头解析场景中,它们让服务端能自然分离处理固定头与可变体,避免手动拷贝、减少 GC 压力,且无需拼接大字节数组。
Scatter 用于协议头+体的分步接收
适用于服务端解析客户端发来的定长头(如 4 字节消息长度)+ 变长体(如 JSON、二进制负载)报文。
- 分配两个 DirectByteBuffer:headerBuf(capacity = 4)、bodyBuf(capacity = 预估最大负载,例如 8192)
- 确保 SocketChannel 已设为非阻塞,并注册到 Selector 监听
OP_READ - 调用
channel.read(new ByteBuffer[]{headerBuf, bodyBuf})—— NIO 自动先填满 headerBuf 的 4 字节,再将剩余字节写入 bodyBuf - 检查返回值:若只返回 2,说明数据未就绪,两个 Buffer 都不能 flip;只有当返回 ≥ 4 时,才对 headerBuf 调用
flip()并读出 length 字段 - 根据 length 值判断 body 是否收全:若
bodyBuf.position() ,需继续等待下一次 OP_READ 就绪后重试
Gather 用于协议响应的逻辑拼装
适用于服务端构造 HTTP 响应、RPC 返回等含状态码、头部、正文、换行符的复合消息,物理上分存、逻辑上一体。
- 预先准备多个已写入内容并
flip()的 Buffer:statusBuf("200 OK\r\n")、headersBuf("Content-Type: application/json\r\n")、bodyBuf(JSON 字符串字节)、crlfBuf("\r\n") - 所有 Buffer 必须同为 heap 或同为 direct;推荐全用 direct,避免 JVM 堆内拷贝
- 调用
channel.write(new ByteBuffer[]{statusBuf, headersBuf, bodyBuf, crlfBuf})—— NIO 按顺序写出每个 Buffer 的limit - position字节(即只写有效内容) - 返回值是实际写出总字节数;若网络缓冲区满,未写完的 Buffer 保持当前 position/limit,下次可直接复用 write,无需重新 flip 或 clear
关键约束与避坑点
忽略这些底层限制容易导致数据错位、读写失败或性能下降。
- 仅支持 FileChannel 和 非阻塞 SocketChannel / ServerSocketChannel;DatagramChannel 不支持
- Scatter 要求前一个 Buffer 必须填满才写下一个,因此只适合头长度严格固定的协议,不自动识别变长字段
- 所有 Buffer 类型必须一致(全 heap 或全 direct),否则行为未定义
- Buffer 顺序决定数据布局:Scatter 按数组索引从左到右填充,Gather 按索引从左到右写出
- 单次操作不保证全部完成,必须检查返回值,并在非阻塞模式下配合 Selector 处理就绪事件
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











