web-dev-qa-db-ja.com

ConcurrentHashMapを揮発性にする必要がありますか?

2つのスレッドによって読み書きされる共有ConcurrentHashMapがあります。

class Test {

    ConcurrentHashMap map;

    read() {
        map.get(object);
    }

    write() {
        map.put(key, object);
    }
}

1つのスレッドの書き込みができるだけ早くリーダースレッドに表示されるように、マップを揮発性にする必要がありますか?

あるスレッドでのマップへの書き込みが、別のスレッドで見られない、または非常に遅れて見られる可能性はありますか? HashMapについても同じ質問です。

37
user3739844

finalにできる場合は、それを実行してください。 finalにできない場合は、はいvolatileにする必要があります。 volatileはフィールド割り当てに適用され、それがfinalでない場合、(少なくともJMMごとに)1つのスレッドによるCHMフィールドの書き込みが別のスレッドに表示されない可能性があります。繰り返しますが、これはConcurrentHashMapフィールドの割り当てであり、CHMを使用していません。

とはいえ、本当にfinalにする必要があります。

1つのスレッドの書き込みができるだけ早くリーダースレッドに表示されるように、マップを揮発性にする必要がありますか?

CHM自体のミューテーションメソッド(putremoveなど)を使用して書き込みを行った場合、フィールドを揮発性にしても効果はありません。すべてのメモリ可視性の保証は、CHM内で行われます。

あるスレッドでのマップへの書き込みが、別のスレッドで見られない、または非常に遅く見られる可能性はありますか? HashMapについても同じ質問です。

ConcurrentHashMap用ではありません。プレーンなHashMapを同時に使用している場合は、使用しないでください。参照: http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html

34
John Vint

volatile は、対応する変数への読み取りおよび書き込みに「発生前のセマンティクス」を適用します。

フィールドはvolatileと宣言できます。その場合、Javaメモリモデルは、すべてのスレッドが変数の一貫した値を参照することを保証します(§17.4)。

変数の値によって参照されるオブジェクトとは関係ありません。したがって、複数のスレッドにまたがって変数を変更しているのでない限り、変数をvolatileにする必要はありません。

javadoc が示すように、すべてのConcurrentHashMapメソッドはメモリバリアとして機能し、

取得は、その開始時に保留されている最後に完了した更新操作の結果を反映します。 (より正式には、特定のキーの更新操作は、更新された値を報告するそのキーの(null以外の)検索との前に発生する関係を負います。

10

いいえ、必要ありません。

volatileは、変数をレジスタにキャッシュできないため、常にメモリへの「ライトスルー」になることを意味します。これは、あるスレッドの変数への変更が他のスレッドから見えることを意味します。

この場合、変数はマップへの参照です。常に同じマップを使用するため、参照を変更するのではなく、そのマップの内容を変更します。 (つまり、マップはmutableです。)これは、マップfinalを参照できること、したがって、参照する必要があることも意味します。

ConcurrentHashMapは、通常、安全に読み取ることができるという点でHashMapとは異なりますandそれに書き込む同時に外部ロックなしで異なるスレッドから。ただし、任意の時点でサイズを信頼できるようにしたい場合、チェックアンドライト操作などを行う場合は、自分で設計する必要があります。

4
Bex