3

已知方法org.osgi.framework.Version.toString()会导致性能问题(请参阅错误 324331 - 从 Version.toString 创建的冗余字符串)。为了解决这个问题,方法被改变了,现在它利用数据竞争的延迟初始化(可能是为了提高性能)

// OSGi Service Platform Release 4 Version 4.3 Core Companion Code 
public String toString() {
    if (versionString != null) {
        return versionString;
    }
    int q = qualifier.length();
    StringBuffer result = new StringBuffer(20 + q);
    result.append(major);
    result.append(SEPARATOR);
    result.append(minor);
    result.append(SEPARATOR);
    result.append(micro);
    if (q > 0) {
        result.append(SEPARATOR);
        result.append(qualifier);
    }
    return versionString = result.toString();
}

正如我所相信的那样,这不是线程安全的,因为versionString可以对字段的读取进行重新排序,并且该方法可以返回null值。我对吗?或者也许没关系,因为没有适当的同步就不会调用它?

更新

根据JLS 第 17 章并发性的作者之一 Jeremy Manson 的这篇博客文章,它实际上是可以发生的。

4

1 回答 1

2

它更多的是关于缓存而不是懒惰。

但你是对的,它可以根据 Java 内存模型返回 null

StringversionString;

public String toString() {
    if (versionString != null) {
        return versionString;  // can return null here!!
    }

理论上可以转化为

    String tmp1 = versionString;  // reads null
    String tmp2 = versionString;  // reads non-null
    if(tmp2!=null)
        return tmp1;              // return null!

然而,可能没有真正的 JVM 会这样做,所以这个错误可能永远不会意识到。

然而,“正确”的做法是

public String toString() {
    String tmp = versionString;
    if (tmp != null) {
        return tmp;
    }

最后一行很好

    return versionString = result.toString();

它不读versionString,相当于

    String tmp3 = result.toString();
    versionString = tmp3;
    return tmp3;

有趣的是,即使我们这样做

    versionString = result.toString();   // [w]
    return versionString;                // [r]

它仍然是安全的。最后一次读取不能返回 null,因为 [w] 发生在 [r] 之前。

于 2013-03-09T16:50:24.887 回答