の下でこの記事をオブジェクトのフィールドを読んだが、読んだ後に育った:https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#pitfall-semi-syncオブジェクトへの参照を読み取り、JMM
class Box {
int x;
public Box(int v) {
x = v;
}
}
class RacyBoxy {
Box box;
public synchronized void set(Box v) {
box = v;
}
public Box get() {
return box;
}
}
とテスト:
@JCStressTest
@State
public class SynchronizedPublish {
RacyBoxy boxie = new RacyBoxy();
@Actor
void actor() {
boxie.set(new Box(42)); // set is synchronized
}
@Actor
void observer(IntResult1 r) {
Box t = boxie.get(); // get is not synchronized
if (t != null) {
r.r1 = t.x;
} else {
r.r1 = -1;
}
}
}
著者はそれがr.r1 == 0
ことは可能であると述べています。私は と同意します。しかし、私は説明と混乱しています:
実際の失敗は、オブジェクトへの参照の読み取りとオブジェクトのフィールドの読み取りがメモリモデルでは異なるという事実に起因します。
私は
はオブジェクトへの参照を読み取り、オブジェクトのフィールドを読み込むことに同意しますが、私はそれが結果に影響を与える方法を見ていない、メモリモデルの下に別個のものである けど。
ご理解ください。
P.S.誰かが混乱している場合@Actor
。単にスレッド内で実行するという意味です。
そうですか? 最初のスレッド(アクター)が参照を公開しましたが、オブジェクトは初期化されていませんでした。次に、オブザーバがボックスへの参照を読み込み( 'boxie.get()')、参照が 'null 'でなかったので、オブザーバは' t.x == 0'を読み込みます。 – Gilgamesz
はい、インスタンスのパブリッシュとそのコンストラクタの呼び出しは、オブジェクトのパブリッシュを安全にしない限り、アトミックではありません。 –