Map から値を同時に読み取るだけの複数のスレッドに、事前構築済みの Map を渡したいと考えています。この場合、同時アクセスについて心配し、HashMap の代わりに ConcurrentHashMap を使用する必要がありますか?
7 に答える
Map を作成して初期化するスレッドと、その後それを読み取るスレッドとの間に「事前発生」関係があることを確認する必要があります。そのような関係がない場合、理論的には、読み取りスレッドが古いデータを参照する可能性があります。
他のスレッドを開始するスレッドでマップを作成して設定すると、...これを行う前に...うまくいくはずです。
安全性を確保するもう 1 つの簡単な方法は、次のようなことです。
public class Foo {
private final Map map;
public Foo(....) {
map = new HashMap();
// populate
}
public Map getMap() {
// If the 'map' is final, and nothing changes it apart from
// the constructor, this method doesn't need to be synchronized.
}
これらはどちらも、作成/初期化と、各スレッドによるマップの最初の使用との間に「前に発生する」関係になります。
map
上記で と宣言することもできますがvolatile
、厳密に発生する必要があるよりも多くのキャッシュ フラッシュが発生する可能性があります。つまり、パフォーマンスが少し低下します。
スレッドの安全性については常に心配する必要があります。あなたの特定の例では、あなたが
- 単一のスレッドでマップを完全に構築します。
volatile
参照する変数を設定して、他のスレッドに公開します。
または、それがオプションである場合は、マップの準備ができるまでスレッドが開始されないことを確認してください。
理論的には、同時読み取りによってコレクションに問題が発生することはありません。
ただし、一度でも変更するとエラーが発生しやすくなるため、並行バージョンを使用する必要があります。
すべてのスレッドが HashMap を読み取っている場合は、HashMap を渡しても安全です。ただし、マップを渡す前に Collections.unmodifiableMap() を呼び出して、将来の一部のプログラマーが現在のコントラクトを尊重しなかったためにスレッドの 1 つが誤ってマップを変更した場合、例外が発生することを確認します。
いいえ、心配する必要はありません。
スレッドがアクセスしている間に、誰かが事前に構築されたマップを変更しようとするまでは。
いいえ、使用する必要はありません。競合は、次の場合にのみ生成されます。
- 一部のスレッドがデータを読み取り、他のスレッドがデータを上書きしようとする場合。
- 2 つ目は、すべてのスレッドがデータを更新しようとするときです。
各スレッドが値の読み取りのみを試みている場合、競合は発生しません。