为什么 StringBuffer 有 toStringCache 而 StringBuilder 没有?

Why StringBuffer has a toStringCache while StringBuilder not?

在 JDK 8 中,StringBuffer class 有一个 toStringCache,而 StringBuilder 没有。

/**
 * A cache of the last value returned by toString. Cleared
 * whenever the StringBuffer is modified.
 */
private transient char[] toStringCache;

但是为什么呢?

鉴于具有逃逸分析和偏向锁定的现代 JVM,差异是否不再相关?

我认为你的第一个猜测是高度准确的,因为 StringBuilder 不是线程安全的,并且一个实例可以跨多个线程共享,实现这样的缓存将需要额外的同步,这将违背目的StringBuilder 排在首位。

至于为什么需要这样做,归结为使用的 new String(...) 构造函数;在 StringBuffer 使用构造函数 String(array, boolean) 的情况下,评论说:

Package private constructor which shares value array for speed.

考虑历史背景可能会有所帮助。 StringBuilder 是与 Java 5 一起引入的,因为人们已经认识到,StringBuffer 不太适合其实际用例。

新推出的 StringBuilder 专为在纯本地环境中构建、使用并随后立即删除的主要用例而设计。因此,它不提供任何同步,也不会费心优化 toString() 方法被多次调用而没有中间更改的罕见情况(这在现实生活中什么时候发生?),尤其是,事实上,在不牺牲无线程同步的性能优势的情况下提供缓存功能,介于“困难”和“不可能”之间。

虽然 StringBuilder 被记录为非线程安全的,因此您知道在其上并发调用方法时可能会发生不一致的事情,但 class String 保证是线程安全的因此,通过不变性,绝不能允许 StringBuilder 缺少同步会导致已构建的字符串不一致,并且根本不在 StringStringBuilder 之间共享数组,是最安全的解决方案。

那么,如果这种优化在现实生活中几乎没有任何好处,那么为什么会有这种优化呢?好吧,因为它已经存在很长时间了,很可能甚至从 Java 1.0 开始就存在,并且不值得更改 class StringBuffer 中的任何内容。它的存在可能没有任何真正的优势,但也没有删除它,这将需要新的测试等等,并且可能会成为某些应用程序的 space bar overheating feature

您可能会注意到,当时 Java 1.x 做出的许多设计决策在今天看来可能很奇怪。在基础 classes 中过度使用 synchronized 就是其中之一,这几乎不会帮助优化另一个。那时,连不变性的含义都没有被很好地理解,这就是为什么我们有像 String.valueOf(char[]) and String.copyValueOf(char[]), plus the opportunity to use new String(char[])

这样的冗余方法