6

このコードで volatile は冗長ですか?

public class Test {
    private volatile Map<String, String> map = null;

    public void resetMap() { map = new ConcurrentHashMap<>(); }

    public Map<String, String> getMap() { return map; }
}

つまり、map = new ConcurrentHashMap<>();可視性の保証はありますか?

私が見る限り、によって提供される唯一の保証は次のConcurrentMapとおりです。

オブジェクトをキーまたは値として ConcurrentMap に配置する前のスレッド内のアクションは、別のスレッド内の ConcurrentMap からのそのオブジェクトのアクセスまたは削除に続くアクションの前に発生します。

java.util.concurrent の他のスレッド セーフ コレクション (CopyOnWriteArrayList など) はどうですか?

4

6 に答える 6

9

volatileマップへの参照を変更しているため、冗長ではありません。つまり、ConcurrentMap は、コレクションへの参照ではなく、コレクションのコンテンツに関する保証のみを提供します。

代替案は

public class Test {
    private final Map<String, String> map = new ConcurrentHashMap<>();

    public void resetMap() { map.clear(); }

    public Map<String, String> getMap() { return map; }
}

java.util.concurrent の他のスレッド セーフ コレクション (CopyOnWriteArrayList など) はどうですか?

コレクションの動作のみがスレッド セーフです。コレクションへの参照はスレッド セーフではありません。コレクション内の要素は、コレクションに追加してもスレッド セーフにはなりません。

于 2012-08-29T11:46:07.170 に答える
6

volatileここで必要です。それは、それが参照するものではなく、参照に適用されます。言い換えれば、オブジェクトがスレッドセーフであることは問題ではなく、他のスレッドはmapfield の新しい値を認識しません (たとえば、以前に参照された同時マップまたは を参照する可能性がありますnull)。

さらに、オブジェクトが不変 (例: ) であったとしても、のような他のスレッドセーフなコレクションは言うまでもなく、Stringも必要です。volatileCopyOnWriteArrayList

于 2012-08-29T11:47:53.313 に答える
4

これは参考文献に限ったことではありません。一般に、volatile修飾子がないと、他のスレッドはオブジェクトへの新しい参照を観察できますが、オブジェクトは部分的に構築された状態で観察されます。一般に、ドキュメンテーションを参照した後でさえ、どのオブジェクトがデータ競合によるパブリケーションに対して安全であるかを知ることは容易ではありません。興味深いことに、JLSはスレッドセーフな不変オブジェクトに対してこれを保証しているため、ドキュメントでこれら 2 つのプロパティについて言及されていれば十分です。

ConcurrentHashMap明らかに不変オブジェクトではないため、それは当てはまりません。ドキュメントでは、データ競合による公開については何も言及していません。ソース コードを注意深く調べると、実際に安全であると結論付けることができますが、このプロパティが明確に文書化されていない限り、そのような調査結果に依存することはお勧めしません。

于 2012-08-29T11:52:45.910 に答える
0

OK-フィールドが揮発性でない場合(私のマシンではJDK 1.7.06 / Win 7 64ビット)に壊れる例を作成できました-マップが揮発性でない場合はプログラムは印刷されません-マップが揮発性の場合Loop exitedは印刷されますLoop exited。QED。

public class VolatileVisibility extends Thread {

    Map<String, String> stop = null;

    public static void main(String[] args) throws InterruptedException {
        VolatileVisibility t = new VolatileVisibility();
        t.start();
        Thread.sleep(100);
        t.stop = new ConcurrentHashMap<>(); //write of reference
        System.out.println("In main: " + t.stop); // read of reference
        System.out.println("Waiting for run to finish");
        Thread.sleep(200);
        System.out.println("Still waiting");
        t.stop.put("a", "b"); //write to the map
        Thread.sleep(200);
        System.exit(0);
    }

    public void run() {
        System.out.println("In run: " + stop); // read of reference
        while (stop == null) {
        }
        System.out.println("Loop exited");
    }
}
于 2012-08-29T12:16:48.357 に答える
0

メモリ整合性プロパティ

揮発性フィールドへの書き込みは、同じフィールドの後続のすべての読み取りの前に発生します。揮発性フィールドの書き込みと読み取りには、モニターの出入りと同様のメモリ整合性の効果がありますが、相互排他ロックは必要ありません。

オブジェクトを同時コレクションに配置する前のスレッド内のアクションが発生します-別のスレッド内のコレクションからその要素にアクセスまたは削除した後のアクションの前に発生します。

于 2012-08-29T11:55:01.057 に答える
0

私の印象では、Doug Lea の並行オブジェクトはデータ競合によって安全に公開できるので、悪用されても「スレッドセーフ」です。彼はおそらくそれを公に宣伝しないだろうが.

于 2012-08-30T00:43:25.530 に答える