buffer 的 mark() 和 reset() 是仅操作 position 指针的轻量级回退机制:mark() 快照当前 position,reset() 将其恢复;二者不改变数据、limit 或 capacity,且受 clear()/flip()/rewind() 等操作清空 mark,需严格遵循调用顺序与生命周期约束。

Buffer 的 mark() 和 reset() 是一对轻量级位置回退机制,不操作数据,只管理 position 指针。它们本身不感知业务含义,但配合得当,能高效支持解析回溯、容错跳过、字段重试等场景。
mark() 本质是“拍快照”,不是“设锚点”
调用 mark() 时,Buffer 把当前 position 值存进内部 mark 字段(默认为 -1)。它不改变 position,也不影响 limit 或数据内容。
- 必须先
mark(),才能reset();否则抛InvalidMarkException -
mark是 buffer 实例独有状态,不能跨 buffer 共享 - 以下操作会清空
mark:调用clear()、flip()、rewind(),或使position / <code>limit
reset() 只改 position,其他都不动
reset() 将 position 设为之前 mark 记录的位置,仅此而已。它不会恢复 limit,不会擦除数据,也不会重置 capacity。
- 调用后
position == mark,但limit仍保持原值(可能是capacity,也可能是flip()后的写入长度) - 如果
reset()后position > limit,后续get()会直接抛BufferUnderflowException - 常见误用:在
compact()或多次put()导致position超出有效范围后再reset(),容易引发越界读
典型业务映射方式:把“字段边界”转成 “position 快照”
所谓“变量处理位置”,实际是你解析协议流时某个关键节点的字节偏移。你需要主动把业务语义和 position 绑定起来。
- 读完 header 长度字段(如 4 字节 int)后立即
mark(),再按该长度读 body;若 body 解析失败,reset()回 header 末尾,可选择跳过整包 - 解析 CSV 行时,每成功 parse 一个字段,就在其起始位置
mark();某字段格式异常时,reset()到上个mark,尝试用备用规则解析或定位错误位置 - 注意:
mark不记录上下文,需由代码自行维护关联信息(例如用栈保存对应字段名或解析阶段)
安全使用的几个硬性前提
mark/reset 不是事务回滚,它的可靠性取决于你对 buffer 生命周期和操作顺序的控制。
- 确保
reset()前未执行clear()、flip()或rewind() - 避免在
position已超limit后调用reset()(尤其在写模式下反复put()) - 多线程环境下,
mark是 buffer 级状态,不可共享;如需并发安全,应为每个线程分配独立 buffer 或加同步 - 使用
slice()或duplicate()得到的子 buffer,mark独立于原 buffer,互不影响
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











