Java の事前発生と同期については、少し意見の相違があります。
次のシナリオを想像してください。
メインスレッド
MyObject o = new MyObject(); // (0)
synchronized (sharedMonitor) {
// (1) add the object to a shared collection
}
// (2) spawn other threads
その他のスレッド
MyObject o;
synchronized (sharedMonitor) {
// (3) retrieve the previously added object
}
// (4) actions to modify the object
のインスタンス変数はでも でもMyObject
ないことに注意してください。のメソッドは同期を使用しません。volatile
final
MyObject
私の理解では、次のとおりです。
1は 3の前に発生 します。これは、同じモニターで同期が行われ、他のスレッドが2でのみ生成され、 1の後に実行されるためです。
4に対するアクションは、すべてのスレッドに対してさらに同期が行われ、メイン スレッドがこれらのアクションの後に何らかの方法で同期しない限り、後でメイン スレッドに表示されるという保証はありません。
Q: 0でのアクションが表示され、前に発生し、 3で同時アクセスされるという保証はありますか?それとも、変数を として宣言する必要がありますvolatile
か?
ここで、次のシナリオを検討してください。
メインスレッド
MyObject o = new MyObject(); // (0)
synchronized (sharedMonitor) {
// (1) add the object to a shared collection
}
// (2) spawn other threads, and wait for their termination
// (5) access the data stored in my object.
その他のスレッド
MyObject o;
synchronized (sharedMonitor) {
// (3) retrieve the previously added object
}
o.lock(); // using ReentrantLock
try {
// (4) actions to modify the object
} finally { o.unlock(); }
私の理解では、次のとおりです。
1 前と同じように3の前に発生します。
が保持するでの同期により、 4でのアクションは他のスレッド間で表示されます。
ReentrantLock
MyObject
4に対するアクションは論理的に3の後に発生しますが、別のモニターで同期した結果として、3から4への先行発生の関係はありません。
4
sharedMonitor
の後unlock
に同期があったとしても、上記の点は当てはまります。メインスレッドが他のタスクの終了を待っている場合でも、4のアクションは5のアクセスの前に発生しません。これは、5へのアクセスが と同期されていないためです。そのため、メイン スレッドには古いデータがまだ表示される場合があります。
o.lock()
Q:私の理解は正しいですか?