スレッド セーフ コレクション (CopyOnWriteArrayList など) に格納されているオブジェクトはスレッド セーフですか? 格納されたオブジェクトが変更可能 (スレッド セーフではない) であるとしましょう。コレクション (ここでは CopyOnWriteArrayList) がスレッド セーフであるという事実は、そこに格納されている参照のスレッド セーフに対する保証を提供しますか?
3 に答える
いいえ、オブジェクトはスレッドセーフではありません。2 つのスレッドが CopyOnWriteArrayList から取得した可変オブジェクトを変更すると、データ競合が発生します。
コレクションがスレッド セーフである場合、これは、2 つのスレッドがコレクションを破損することなくコレクションからオブジェクトを追加/削除できることを意味します (たとえば、ArrayList はスレッド セーフではないため、2 つのスレッドがそれぞれオブジェクトをコレクションに追加しようとすると、一方または両方のオブジェクトが失われる可能性があります) が、コレクション内のオブジェクトをスレッドセーフにするために同期する必要があります。
いくつかの保証があります。通常、スレッド セーフ ストレージは、メモリ効果の点で揮発性変数に似ています。
volatile Foo var; final Vector<Foo> vars = new Vector<>()
// thread 1 // thread 1
foo.bar = bar; [1] foo.bar = bar; [1]
var = foo; vars.set(0, foo);
// thread 2 // thread 2
bar = foo.bar; [2] bar = vars.get(0).bar; [2]
//read[2] sees write[1] // read[2] sees write[1]
基本的に、挿入前の書き込みは、取得後の読み取りに表示される必要があります。
提供される唯一のスレッドセーフな保証は、オブジェクトが「安全に公開される」ということです。つまり、すべてのスレッドで一度に可視になります (これには、オブジェクトへの参照とその内部状態が含まれます)。
例: スレッド A が X を書き込み、スレッド B が読み取る場合、B は、A が残した X を確認することが保証されます。つまり、読み取り操作と書き込み操作は、発生する順序と一致しています。
final
、 またはvolatile
、 またはAtomicReference
、またはロック (これはスレッドセーフ コレクションが行っていることです)、または静的初期化子を使用するなど、同じことを達成する他の方法があります。詳細については、書籍「Java Concurrency in Practice」を参照してください。