StringBuffer因所有公开方法加synchronized而比StringBuilder慢2–4倍,核心差异仅在于同步关键字,二者底层实现完全相同;线程安全仅在多线程共享同一实例时必要,局部使用应选StringBuilder,并预设容量以减少扩容开销。
因为 StringBuffer 的每个公开方法都加了 synchronized,而 StringBuilder 完全不加锁——同步机制本身就会带来锁获取、释放、内存屏障等开销,哪怕只有一个线程在跑,也绕不开。
StringBuffer 和 StringBuilder 底层共享同一套实现(都继承自 AbstractStringBuilder),用的都是可变的 char[](JDK9+ 改为 byte[]),扩容逻辑、append 行为、内部缓冲管理全都一样。唯一的区别是:StringBuffer 的 append()、toString()、delete() 等所有公共方法签名上都明确写了 synchronized;StringBuilder 则完全没这层修饰。
这意味着:
在单线程下做 10 万次 append("x"):
立即学习“Java免费学习笔记(深入)”;
这个差距不来自算法或数据结构,纯粹来自同步带来的额外字节码指令和运行时机制。锁竞争越少,相对差距越稳定;但只要加了 synchronized,就不可能比无锁版本快。
StringBuffer 的线程安全是有代价的,但它只在一种场景下真正必要:
如果只是方法内局部创建、拼完即弃,或者通过 ThreadLocal 隔离,用 StringBuffer 就等于主动给单线程任务加锁——白耗资源,还掩盖真实并发风险。
无论选哪个,如果能预估最终长度,初始化时指定容量能减少数组复制次数:
这点对两者都适用,但对 StringBuilder 更值得做——它本就轻量,省下的复制开销更直接体现为性能提升。