問題タブ [java-memory-model]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
java - ダブルチェックロックに対するJava同期効果?
Double-checked locking: Clever, but breakedなどのさまざまな記事を読み、次のコードがマルチスレッドの使用で壊れている理由を理解しました。
ただし、その説明によると、スレッドが同期ブロックを終了すると、書き込みバリアが実行されます。ロックを解放する前に、そのブロックで変更されたすべての変数をメイン メモリにフラッシュする必要があります。したがって、スレッド A が同期ブロックに実行されると、次のプロセスが順番に実行されます。
- 新しい Resource オブジェクトのメモリが割り当てられます。
- Resource のコンストラクタが呼び出され、
- 新しいオブジェクトのメンバー フィールドを初期化します。
- SomeClass のフィールド リソースには、新しく作成されたオブジェクトへの参照が割り当てられます。
最後に、スレッド A が同期ブロックから出る前に、スレッド A はそのローカル リソース オブジェクトをメイン メモリに書き戻し、スレッド B は、同期ブロックに到達すると、この新しく作成されたリソースをメイン メモリから読み取ります。
スレッド B がこれらのメモリ操作を、スレッド A が実行する順序とは異なる順序で見ることができるのはなぜですか? スレッド B は、共有可能なメイン メモリからしかリソース オブジェクトを読み取ることができないため、スレッド A が同期ブロックから出るときにローカル メモリをメイン メモリにフラッシュするまで、リソース オブジェクトが作成されたことをスレッド B は認識しないと思いましたか?
私の理解を修正してください....ありがとうございます。
java - 特定のデータ構造がキャッシュに適していると言うとき、それはどういう意味ですか?
リンクされたリストのデータ構造とそのバリアント スキップリストは、並列ハードウェアでキャッシュに適しているとよく読んでいます。これは何を意味するのでしょうか ?どなたか分かりやすく教えてください。
編集:コンテキストは このリンクにあります。
java - 2 つのフィールドを volatile と宣言するだけで十分ですか?
現在、Java MEアプリケーションを作成しています。私が知っているように、その機能は Java 1.3 に制限されているため、古いJava メモリ モデルを使用しています。このモデルが提供する volatile キーワードに関する唯一の保証は、すべての読み取りと書き込みがメイン メモリを直接経由し、キャッシュされないことです。
次のコードを検討してください。
メソッドは異なるスレッドから呼び出されます。メソッドは変数にmakeBill()
書き込み、メソッドはそのフィールドから読み取ります。volatile
cancelBillRequest()
2 つのフィールドを宣言するだけでvolatile
十分ですか? 揮発性の読み取りと書き込みの並べ替えについてどう思いますか? 私のコードは安全ですか?
java - この動作がJavaメモリモデルで許可されているのはなぜですか?
JMMの因果関係は、その中で最も紛らわしい部分のようです。JMMの因果関係、および並行プログラムで許可される動作に関していくつか質問があります。
私が理解しているように、現在のJMMは常に因果関係のループを禁止しています。(私は正しいですか?)
ここで、JSR-133ドキュメント、24ページ、図16に従って、次の例があります。
最初はx = y = 0
スレッド1:
スレッド2:
直感的には、r1 = r2 = r3 = 42
不可能のようです。ただし、可能な限り言及されているだけでなく、JMMでは「許可」されています。
可能性として、私が理解できない文書からの説明は次のとおりです。
コンパイラーは、これまでに割り当てられた唯一の値が0と42であると判断できます。それから、コンパイラーは、実行した時点で、42の書き込みを実行したか、 読み取りと表示を行っただけ
x
であると推測できます。値42。いずれの場合も、の読み取りで値42を確認することは合法です。その後、 ;に変更される可能性があります。これにより、以前に変換して実行できるようになり、問題の動作が発生します。この場合、書き込み先が最初にコミットされます。r1 = x
x
x
x
r1 = x
r1 = 42
y = r1
y = 42
y
私の質問は、それは本当にどのようなコンパイラの最適化ですか?(私はコンパイラーを認識していません。)42は条件付きでのみ記述されるため、if
ステートメントが満たされた場合、コンパイラーはどのようにしてx
?
第二に、コンパイラーがこの投機的最適化を行い、コミットy = 42
して最終的に作成r3 = 42
したとしても、因果関係の区別が残っていないため、因果関係ループの違反ではありませんか?
実際、同じ文書(15ページ、図7)には、同様の因果ループが許容できないと言及されている例が1つあります。
では、なぜこの実行順序がJMMで合法なのですか?
java - 同期と可視性の範囲
私はJavaの同時実行性について読んでいて、同じロックを使用する2つのスレッドの同期ブロックが変数の可視性にも影響するという事実を忘れていました.それらは「揮発性」として定義されていませんでした. このようなコードがある場合
... そして、threadOne と threadTwo は異なるスレッドによって呼び出されます。
コードが while ループから抜けることが保証されていますか?
式から変数 c を削除するとどうなるでしょうか。同期ブロック内にあったため、b のみが threadTwo に表示されることが保証されているかどうか疑問に思っています。
java - プログラムが JLS で定義されているように「正しく同期」されているかどうかを判断するツールはありますか?
Java 言語仕様 7 (JLS7-17.4.5) では、「正しく同期された」プログラムを次のように定義しています。
JLS7-17.4.5 には、次のようにも記載されています。
正しく同期しないと、非常に奇妙で、混乱を招き、直感に反する動作が発生する可能性があります。
したがって、プログラマーの観点からは、プログラムが上記の定義に従って「正しく同期されている」かどうかを判断するツールがあれば非常に便利です。
そのようなツールはありますか?グーグルで検索しても何も見つかりませんでした。そのようなツールがない場合、作成することは可能でしょうか?
memory-barriers - JMMクックブックの混乱のメモリバリアの例
私は、JMM クックブック http://g.oswego.edu/dl/jmm/cookbook.htmlでのバリアの例のこのコンパイラ挿入と混同しています。
i = u (u からの揮発性ロードと、通常の i へのストアを伴いませんか?)
j = b (私には b からの通常のロードと j への通常のストアが見えます)
クックブックのルックアップ テーブルによると、LoadLoad と LoadStore の 2 つのバリアはどこから来るのでしょうか?
ありがとう!
///////////////// JSRの例 ////
揮発性 int u;
int i、b、j;
私は= u; //あなたをロード
j = b; //ロードb
java - Java Concurrency - 不変オブジェクトの公開 (Java Concurrency In Practice)
Java Concurrency In Practice で、著者は次のように述べています。
- 不変オブジェクトは、任意のメカニズムを介して公開できます
- 不変オブジェクトは、同期を使用して公開していない場合でも、追加の同期なしで任意のスレッドで安全に使用できます。
次のイディオムは、不変オブジェクトを安全に公開できるということですか?
データ競合はありますか?(つまり、スレッド B は、スレッド A によって追加されたリスト内の不変オブジェクトを認識できない可能性があります)
どうもありがとうございました。
さらに、著者は、リソースが不変である場合、次のコードは安全であると述べました。
セクション16.3 初期化の安全性の保証により、適切に構築された不変オブジェクトは、データ競合を使用して公開された場合でも、公開方法に関係なく、同期せずにスレッド間で安全に共有できます。(これは、が不変で
unsafeLazyInitialization
あれば実際には安全であることを意味します。)Resource
この質問の 2 番目の部分については、別の質問 (ここをクリック) で詳しく説明されています。
java - 不変性と並べ替え
以下のコード (Java Concurrency in Practice リスト 16.3) は、明らかな理由でスレッド セーフではありません。
ただし、数ページ後のセクション 16.3 では、次のように述べています。
UnsafeLazyInitialization
が不変の場合、 実際には安全です。Resource
私はその声明を理解していません:
- が不変の場合、変数を
Resource
監視するすべてのスレッドは、resource
変数が null または完全に構築されていることを認識します (Java メモリ モデルによって提供される final フィールドの強力な保証のおかげです)。 - ただし、命令の並べ替えを妨げるものはありません。特に、 の 2 つの読み取りを
resource
並べ替えることができます ( に 1 つ、 に 1 つの読み取りがありますif
)return
。resource
そのため、スレッドは条件で非 null を確認できますif
が、null 参照 (*) を返します。
不変UnsafeLazyInitialization.getInstance()
でもnullを返すことができると思います。Resource
それは事実であり、なぜ(またはなぜそうでないのか)?
(*) 並べ替えに関する私の主張をよりよく理解するために、同時実行性に関する JLS の第 17 章の著者の 1 人である Jeremy Manson によるこのブログ投稿では、String のハッシュコードが良性のデータ競合を介して安全に公開される方法と、ローカル変数を使用すると、ハッシュコードが誤って 0 を返す可能性があります。これは、上記で説明したのと非常によく似た並べ替えが発生する可能性があるためです。
ここで行ったことは、追加の読み取りを追加することです。つまり、リターンの前にハッシュの 2 回目の読み取りを行います。奇妙に聞こえるかもしれませんが、起こりそうもないことですが、最初の読み取りで正しく計算されたハッシュ値が返され、2 回目の読み取りで 0 が返されることがあります。これは、モデルが操作の広範な並べ替えを許可するため、メモリ モデルの下で許可されます。2 番目の読み取りは、コード内で実際に移動できるため、プロセッサは最初の読み取りよりも先に読み取ります。
java - プリミティブ配列書き込みの Java 同時可視性
最近、コードベースでこの宝石を見つけました:
これは次のように使用されます。
スレッド 1
スレッド 2
スレッド 1 は、継続的に実行されるバックグラウンド更新スレッドです。スレッド 2 は HTTP ワーカー スレッドであり、読み取った内容が何らかの形で一貫性があるか原子的であるかを気にせず、書き込みが「最終的に」そこに到達し、並行性の神への供物として失われないことだけを気にします。
さて、これは私のすべての警告ベルをトリガーします。無関係なコードの奥深くに記述されたカスタム同時実行アルゴリズム。
残念ながら、コードの修正は簡単ではありません。同時プリミティブ行列に対する Java サポートは適切ではありません。これを修正する最も明確な方法は を使用するように見えますがReadWriteLock
、それはおそらくパフォーマンスに悪影響を及ぼすでしょう。正確さは明らかにより重要ですが、パフォーマンスに敏感な領域からそれを切り取る前に、これが正しくないことを証明する必要があるようです.
java.util.concurrent のドキュメントによると、次のようにhappens-before
関係が作成されます。
スレッド内の各アクションは、プログラムの順序で後で来るそのスレッド内のすべてのアクションの前に発生します。
揮発性フィールドへの書き込みは、同じフィールドの後続のすべての読み取りの前に発生します。volatile フィールドの書き込みと読み取りには、モニターの開始と終了と同様のメモリ整合性効果がありますが、相互排他ロックは必要ありません。
したがって、次のように聞こえます。
- マトリックス書き込みは公開前に発生します() (ルール 1)
- publish() は syncChanges() の前に発生 (ルール 2)
- syncChanges() マトリックス読み取りの前に発生 (ルール 1)
したがって、コードは実際にマトリックスの事前発生チェーンを確立しています。
しかし、私は確信していません。並行性は難しく、私はドメインの専門家ではありません。私は何を逃したのですか?これは本当に安全ですか?