3

メソッドorg.osgi.framework.Version.toString()はパフォーマンスの問題を引き起こすことが知られていました ( Bug 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 章の著者の 1 人である 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]

それはまだ安全です。[w] は [r] の前に発生するため、最後の読み取りは null を返してはなりません。

于 2013-03-09T16:50:24.887 に答える