0

一部のスレッドがデータを作成し、そのデータのチャンクを他のスレッドによって消費されるように定期的に渡すパターンのような生産者消費者があります。

Java メモリ モデルを念頭に置いて、コンシューマ スレッドに渡されるデータが完全に「可視化」されるようにするにはどうすればよいですか?

このために特別に構築された ConcurrentLinkedQueue のような java.util.concurrent のデータ構造があることは知っていますが、それらを利用せずにできるだけ低レベルでこれを行い、カバーの下で何が起こっているかを完全に透過的にしたいと考えています。メモリ可視化部分。

4

2 に答える 2

1

「低レベル」が必要な場合は、とを調べてvolatileくださいsynchronized

于 2012-06-01T00:30:02.497 に答える
1

データを転送するには、すべてのスレッドが利用できるフィールドが必要です。あなたの場合、複数のエントリを処理するには、ある種のコレクションである必要があります。finalたとえばConcurrentLinkedQueue を参照して field を作成した場合は、ほぼ完了です。フィールドを公開して誰もが見ることができるようにするか、getter で使用できるようにすることができます。

非同期キューを使用する場合は、そのキューへのすべてのアクセスを手動で同期する必要があるため、やるべきことが増えます。つまり、すべての使用状況を追跡する必要があります。ゲッターメソッドがあると簡単ではありません。同時アクセスからキューを保護する必要があるだけでなく、相互に依存する呼び出しが同じ同期ブロックで終了することを確認する必要があります。例えば:

    if (!queue.isEmpty())  obj = queue.remove();

全体が同期さqueueれていない場合は、空ではないことを完全に伝えることができ、次の要素を取得しようとすると NoSuchElementException がスローされます。(ConcurrentLinkedQueue のインターフェイスは、1 回のメソッド呼び出しでこのような操作を実行できるように特別に設計されています。使用したくない場合でも、よく見てください。)

簡単な解決策は、メソッドが慎重に選択されすべてが同期されている別のオブジェクトでキューをラップすることです。ラップされたクラスは、それが LinkedList または ArrayList であっても、CLQ のように動作し (正しく実行すれば)、プログラムの残りの部分に自由に解放できます。

そのfinalため、(たとえば) LinkedList を含み、LinkedList を使用してデータを格納およびアクセスする同期メソッドを持つラッパー クラスへの不変 ( ) 参照を持つ、実際にはグローバル フィールドとなるものがあります。CLQ のようなラッパー クラスは、スレッド セーフになります。

これに関するいくつかの変形が望ましいかもしれません。ラッパーをプログラム内の他の高レベル クラスと組み合わせることが理にかなっている場合があります。ネストされたクラスのインスタンスを作成して使用可能にすることも理にかなっています。おそらく、キューに追加するだけのものとキューから削除するだけのものです。(CLQ ではこれを行うことができませんでした。)

最後の注意: すべてを同期したら、次のステップは、スレッドの安全性を損なうことなく (スレッドが過度に待機しないようにするために) 同期を解除する方法を理解することです。これに一生懸命取り組むと、ConcurrentLinkedQueue を書き直すことになります。

于 2012-06-01T15:52:45.513 に答える