4

JLSからのこの説明にあるべきではありませんmyS.equals("/usr")か?

Final フィールドは、必要なセキュリティ保証を可能にするように設計されています。次の例を考えてみましょう。1 つのスレッド (スレッド 1 と呼びます) が実行されます。

Global.s = "/tmp/usr".substring(4);

別のスレッド (スレッド 2) の実行中

String myS = Global.s;
if (myS.equals("/tmp"))System.out.println(myS);

文字列オブジェクトは不変であることを意図しており、文字列操作は同期を実行しません。

4

5 に答える 5

4

彼らは、競合状態のために、返された部分文字列が /tmp または /usr のいずれかに見える可能性があるという仮説的な状況を説明しています。結果として、どの文字列が比較に使用されるかは問題ではありません。この例の要点は、この例で説明されている条件が保持されている場合、どちらも正しい可能性があるということです。

于 2013-09-19T12:49:33.577 に答える
1

何も問題はありません。両方のコード スニペットは異なるスレッドを指しており、Java での String クラスの真の不変性を正当化するために例が取られています。以前、文字列の値はスレッド 2 の実行時に "/THREADS...." でしたが、スレッド 1 によって "/usr" に変更されました。説明で明確に説明されています。

于 2013-09-19T12:51:50.270 に答える
1

いいえ、そうすべきではありません。

この例は、一部の JVM 実装に存在したバグを参照しているため、良い例です (残念ながら、どの実装かは覚えていません)。String.substring新しい文字列を作成しませんでしたが、最終offsetではないlengthフィールドと正しい場所を指しているフィールドを持つ古いものを指していました。ただし、フィールドは最終的なものではなかった (そして他の同期はなかった) ため、コード例に続く段落で言及されているシナリオとまったく同じことが起こりえます。

特に、String クラスのフィールドが final でない場合、スレッド 2 が文字列オブジェクトのオフセットのデフォルト値 0 を最初に認識し、" /tmp". String オブジェクトに対する後の操作では、正しいオフセット 4 が表示される可能性があるため、String オブジェクトは「/usr」として認識されます。

実際、文字列は不変であると言われていましたが、コンストラクターが完全に実行される前にオブジェクトが他のスレッドから見える可能性があるため、そうではありませんでした。この例はまさにそれを示しています。

于 2013-09-19T12:59:28.133 に答える
1

String内部的には、オフセット長さを持つ文字配列です。この文字配列は、以前は複数の文字列間で再利用されていました。メモリ使用の最適化として、元の文字列と同じ文字配列に裏打ちされsubstring()た新しいものを返します。Stringこのメソッドが行うことは、結果文字列のこの文字配列への新しいオフセットと長さを決定し、プライベート コンストラクターを呼び出してこの結果オブジェクトを作成し、それを返します。

(Joachim が指摘しているように、これはもはやString機能する方法ではありませんが、JLS の例は古い内部構造に基づいています。)

さて、そのプライベート コンストラクターの実装、JIT または CPU による命令の並べ替え、または一般的にはスレッド間で共有されるメモリの奇抜な動作によって引き起こされる可能性があるのは、この新しいStringオブジェクトが最初にその長さを に設定すること4です。オフセットは に留まり、この0値を にしますString "/tmp"。わずか 1 秒後にオフセットが に設定され4、その値が正しく になります"/usr"

別の言い方をすれば、スレッド 2は、コンストラクターの実行中にこの文字列を観察できます。これは直観に反しているように見えます。なぜなら、人々はスレッド 1のコードを、最初に代入の右側を完全に実行し、その後で の値を変更するだけであると直感的に理解しているからですGlobal.s。残念ながら、適切なメモリ同期がなければ、他のスレッドは異なる一連のイベントを観察できます。フィールドを使用finalすることは、JVM にこれを正しく処理させる 1 つの方法です。( Global.sas宣言volatileも機能すると思いますが、100% 確実ではありません。)

于 2013-09-19T13:00:01.200 に答える