StringBuffer 仅使用 synchronized 方法而非内部同步块,其同步粒度为整个方法;验证同步粒度影响需自定义类对比方法级与块级锁,JMH 测试显示高并发下细粒度锁吞吐更高。

StringBuffer 本身没有公开的 synchronized 块,它所有修改方法(如 append()、insert()、delete())都是 synchronized 方法,锁对象为 this。所以“StringBuffer 内部 synchronized 块 vs synchronized 方法”这个对比在实际源码中并不存在——它只有同步方法,没有手动写的同步块。
为什么不能直接比?
StringBuffer 的设计是统一用方法级同步,不暴露内部锁或分段逻辑。它的同步粒度就是整个方法,没有更细的 synchronized(obj) { ... } 块。因此,所谓“内部同步块”属于误解;若想验证粒度差异,需自行构造对比场景,而非分析 StringBuffer 源码。
如何合理验证同步粒度对性能的影响
你可以通过自定义类模拟两种方式,控制变量做基准测试:
- 写一个
MyBufferA:所有操作方法都加synchronized修饰(模拟 StringBuffer) - 写一个
MyBufferB:只在真正访问共享数组的地方用synchronized(this)包裹关键行(模拟细粒度同步块) - 确保两者底层使用相同字符数组、相同逻辑(如
append都调用System.arraycopy),仅锁范围不同 - 用 JMH(Java Microbenchmark Harness)跑 100 万次单线程
append,观察吞吐量差异;再用多线程(如 8 线程)并发追加,看平均延迟和竞争率
实测会看到什么
在单线程下,两者性能几乎无差——JVM 对无竞争的 synchronized 已高度优化(偏向锁、轻量级锁)。但在高并发场景下:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
MyBufferA(方法级)会出现明显排队,吞吐随线程数增加而下降更快 -
MyBufferB(块级)若只锁扩容/复制等真正共享操作,其余逻辑(如参数校验、局部计算)并行执行,整体吞吐更高 - 差距大小取决于方法体中“非共享”代码占比——越长,方法级同步浪费越明显
别被 StringBuffer 的 toStringCache 误导
有人误以为 toString() 缓存能缓解同步开销,但注意:
-
toStringCache更新仍被synchronized方法保护,无法绕过锁 - 缓存只加速字符串构建,不减少 append/insert 等主干操作的同步等待
- 实测中,即使频繁调用
toString(),StringBuffer 仍比 StringBuilder 慢 50%–85%
本质上,这不是 StringBuffer “用了哪种同步”,而是“它只提供方法级同步”——你要验证的是“粗粒度 vs 细粒度锁”的通用规律,不是它内部有两类实现。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










