15

JLSの第17章では、 「起こる-一貫性を保つ前に」という概念を紹介しています。

一連のアクションAが発生します-一貫する前に、Aのすべての読み取りrについて、W(r)がrから見た書き込みアクションである場合、hb(r、W(r))またはwv = rvおよびhb(W(r)、w)およびhb(w、r)"となるような書き込みwがAに存在します。

私の理解では、それは次の言葉に等しい:...、それは...でも...でもない場合です。

したがって、最初の2つの質問は次のとおりです。

  • 私の理解は正しいですか?
  • 「wv=rv」とはどういう意味ですか?

また、例を示します:17.4.5-1

Thread 1 Thread 2

B = 1; A = 2; 

r2 = A; r1 = B; 

最初の実行順序:

1: B = 1;

3: A = 2;

2: r2 = A;  // sees initial write of 0

4: r1 = B;  // sees initial write of 0

注文自体は、2つのスレッドが交互に実行されることをすでに示しているので、私の3番目の質問は次のとおりです。

私の理解では、r2とr1の両方の理由は、最初の書き込みが0であることがわかるのは、AとBの両方が揮発性フィールドではないためです。ですから、私の4番目の質問は、私の理解が正しいかどうかということです。

2番目の実行順序:

1: r2 = A;  // sees write of A = 2

3: r1 = B;  // sees write of B = 1

2: B = 1;

4: A = 2;

発生前の一貫性の定義によると、この実行順序が発生する前に発生することを理解することは難しくありません(私の最初の理解が正しければ)。したがって、私の5番目と6番目の質問は次のとおりです。現実の世界にこの状況(読み取りは後で発生する書き込みを参照)が存在しますか?もしそうなら、私に実際の例を教えていただけますか?

4

5 に答える 5

18

コヒーレント共有メモリへのアクセスを強制しない限り、各スレッドは、Javaが変数の値を保持するために使用できる独自のプライベートレジスタを備えた異なるコア上に置くことができます。これは、1つのスレッドがレジスタに格納されている値に書き込むことができ、この値がループの期間や関数全体のように、しばらくの間別のスレッドに表示されないことを意味します。(ミリ秒は珍しいことではありません)

より極端な例は、読み取りスレッドのコードが、値を変更しないため、メモリから読み取る必要がないという前提で最適化されていることです。この場合、最適化されたコードは、別のスレッドによって実行された変更を認識しません。

どちらの場合も、を使用volatileすると、読み取りと書き込みが一貫した順序で行われ、両方のスレッドが同じ値を参照することが保証されます。これは、常にメインメモリから読み取ると説明されることもありますが、キャッシュは相互に直接通信できるため、そうである必要はありません。(したがって、パフォーマンスへの影響は予想よりもはるかに小さくなります)。

通常のCPUでは、キャッシュは「コヒーレント」(古い値や競合する値を保持できない)で透過的であり、手動で管理されません。スレッド間でデータを表示するということは、asmで実際のロードまたはストア命令を実行して(データキャッシュを介して)メモリにアクセスし、オプションでストアバッファがドレインして順序付けを行うのを待つことを意味します。その他の後の操作。

于 2012-08-15T13:55:21.100 に答える
6

起こる-前に

並行性理論の定義を見てみましょう。

Atomicity-単一のトランザクションとして完全に実行でき、部分的に実行できない操作のプロパティです。例Atomic operations[例]

可視性-1つのスレッドが変更を加えた場合、それらは他のスレッドにも表示されます。volatileJava5より前happens-before

順序付け-コンパイラーは、ソースコードの操作/命令の順序を変更して、いくつかの最適化を行うことができます。

たとえば、これは解決と発行に役立つhappens-before種類です。発生する前の良い例は、[About]、monitor [About]です。memory barrierVisibilityOrderingvolatilesynchronized

の良い例は、atomicityアトミックである必要があり、マルチスレッド環境で変数を変更できる()パターンの(Compare and swapCAS実現です。次の場合は、独自の実装を作成できます。check then actCTACTA

  • volatile + synchronized
  • java.util.concurrent.atomicwith sun.misc.Unsafe(メモリ割り当て、コンストラクター呼び出しなしでのインスタンス化...)からJava 5の使用JNIとCPUの利点。

CASアルゴリズムには、3つのパラメーター(A(アドレス)、O(古い値)、N(新しい値))があります。

If value by A(address) == O(old value) then put N(new value) into A(address), 
else O(old value) = value from A(address) and repeat this actions again

起こる-前に

公式ドキュメント

2つのアクションは、起こる前の関係によって順序付けることができます。あるアクションが発生した場合(別のアクションの前)、最初のアクションは2番目のアクションの前に表示され、順序付けられます。

ここに画像の説明を入力してください

例としてvolatile [About]

揮発性フィールドへの書き込みは、そのフィールドの後続のすべての読み取りの前に発生します。

例を見てみましょう:

// Definitions
int a = 1;
int b = 2;
volatile boolean myVolatile = false;

// Thread A. Program order
{
    a = 5;
    b = 6;
    myVolatile = true; // <-- write
}

//Thread B. Program order
{
    //Thread.sleep(1000); //just to show that writing into `myVolatile`(Thread A) was executed before

    System.out.println(myVolatile); // <-- read
    System.out.println(a);  //prints 5, not 1
    System.out.println(b);  //prints 6, not 2
}

可視性-揮発性変数をThread A 変更/書き込むと、以前のすべての変更もRAMにプッシュされます-結果として、非揮発性変数はすべて最新になり、別のスレッドで表示されます

注文

  • 揮発性変数に書き込む前Thread Aのすべての操作は、前に呼び出されます。JVMはそれらを並べ替えることができますが、揮発性変数に書き込む前Thread Aの1つの操作がその後に呼び出されないことを保証します。

  • 揮発性変数を読み込んだ後のThread Bすべての操作は、後に呼び出されます。JVMはそれらを並べ替えることができますが、揮発性変数を読み込んだ後Thread Bの1つの操作がその前に呼び出されないことを保証します。

[並行性と並列性]

于 2019-12-26T16:41:59.903 に答える
4

Javaメモリモデルは、appear-beforeと呼ばれるプログラムのすべてのアクションの半順序を定義します。スレッドがアクションの副作用を確認できること を保証するために(別のスレッドで発生したかどうかは関係ありません)、との間に発生前の関係が定義されます。 このような関係が存在しない場合、JVMはプログラムの操作を並べ替えることができます。これで、変数が多くのスレッドによって共有およびアクセスされ、読み取りと書き込みが発生前の関係 によって順序付けられていない場合に(少なくとも)1つのスレッドによって書き込まれる場合、データ競合が発生します。
YXXXY


正しいプログラムでは、データの競合はありません。
例は2つのスレッドで、ロックAB同期されますX
Thread Aロックを取得し(現在Thread Bはブロックされています)、書き込み操作を実行してからロックを解放しますX。これでThread Bロックが取得されX、のすべてのアクションはロックを解放する前に実行されたため、スレッドのにロックを取得したアクションの前に順序付けられます(また、に表示されます)。これは、同じロックで 同期されたアクションで発生することに注意してください。同期されたスレッド間の関係の前に起こることはありませんThread AXThread BX AThread B
別のロックで

于 2012-08-15T14:05:18.343 に答える
2

実質的には正しい。これから取り除く主なことは、何らかの形式の同期を使用しない限り、ステートメントが再利用された可能性があるため、プログラム順序での書き込みの後に続く読み取りがその書き込みの効果を確認するという保証はありません。

現実の世界でこの状況(読み取りは後で発生する書き込みを参照)が存在しますか?もしそうなら、私に実際の例を教えていただけますか?

壁掛け時計の観点からは、明らかに、読み取りはまだ行われていない書き込みの影響を確認できません。

プログラムの順序の観点からは、適切な同期がない場合(関係の前に発生)にステートメントを並べ替えることができるため、プログラムの書き込みの前に行われる読み取りは、実行されているため、実行中にその書き込みの影響を確認できます。 JVMによる書き込み後。

于 2012-08-15T14:33:53.323 に答える
1

Q1:私の理解は正しいですか?

A:はい

Q2:「wv = rv」とはどういう意味ですか?

A:wvの値はrvの値と同じです

Q3:左の数字はどういう意味ですか?

A:「表17.4-A。ステートメントの並べ替えによる驚くべき結果-元のコード」に示すようなステートメントIDだと思います。ただし、「発生する別の実行順序-一貫性がなくなる前に:」の内容には適用されないため、無視できます。したがって、左の番号は完全にたわごとです。それに固執しないでください。

Q4:私の理解では、r2とr1の両方で、最初の書き込みが0であることがわかるのは、AとBの両方が揮発性フィールドではないためです。ですから、私の4番目の質問は、私の理解が正しいかどうかということです。

A:それが1つの理由です。再注文も可能です。「コードを並べ替えたときに観察されるような直感に反する動作を回避するには、プログラムを正しく同期する必要があります。」

Q5&6:2番目の実行順序で...それで、私の5番目と6番目の質問は次のとおりです。現実の世界でこの状況(読み取りは後で発生する書き込みを参照)が存在しますか?もしそうなら、私に実際の例を教えていただけますか?

A:はい。コードの同期はありません。各スレッドの読み取りでは、初期値の書き込みまたは他のスレッドによる書き込みのいずれかを確認できます。

時間1:スレッド2:A = 2

時間2:スレッド1:B = 1 //同期なしで、スレッド1のB=1をここでインターリーブできます

時間3:スレッド2:r1 = B//r1の値は1

時間4:スレッド1:r2 = A//r2値は2

注「実行は、一連のアクションが発生する場合は一貫性のある前に発生します-一貫性のある前に発生します」

于 2021-04-11T21:06:08.857 に答える