一般的な構造はスレッドセーフではありません
プロセス全体を開始するスレッドがチェックmyMap
し、場合によっては別のスレッドで実行を開始します。
if (myMap != null) {
doSomethingInAnotherThread();
}
// something can set `myMap` to null here...
実行がスケジュールされているコードは、ある時点で実行されます
void inAnotherThread() {
myMap.access();
}
myMap
しかし、以前と同じであるという保証はもうありません。myMap
参照するものを変更できるスレッドがある場合は、
void inAnotherThread() {
if (myMap != null) {
myMap.acess();
}
}
myMap
2回アクセスし、毎回異なる可能性があるため、それでもスレッドセーフではありません。たとえば、内部では null ではありませんif
が、null
一度アクセスすると。解決策の 1 つは、参照をコピーして、作業中にその参照のローカル コピーを変更できないようにすることです。
void inAnotherThread() {
Map localReference = myMap;
if (localReference != null) {
localReference.acess();
}
}
それがスレッドセーフかどうかは、に依存しmyMap
ます。それがvolatile
(またはfinal
)であるかどうかにかかわらず。そうである場合: 他のスレッドは、参照されているものの最新バージョンを参照することが保証されmyMap
ます。そうでない場合: 何も保証されません。(注:内部で同期するため、事前発生runOnUiThread
関係が確立されていると思います。したがって、参照の最新バージョンを表示するための何らかの保証が必要です)
正しいインスタンスへの参照を取得したら、次のポイントMap
は、それを安全に使用できることです。simpleHashMap
はスレッドセーフではありません。呼び出し.get()
ても、別のスレッドがput
/ remove
/.. を呼び出し、.get
アクセス中にデータを変更すると、まだ爆発する可能性があります。
他のスレッドが干渉できないように、アトミックのようCollections.synchronizedMap(map)
な単一の操作を行うラップすることができます。get
しかし、それでもすべてに対してスレッドセーフではありません。たとえば、外部で同期しないと、値の繰り返しは失敗します。ConcurrentHashMap
この問題は、反復もサポートする を使用することで解決できます。
スレッドセーフは、多くの要因と、スレッドセーフとは何かの定義に依存します。myMap
一度設定すると決して変更されないことを保証でき!= null
、バックグラウンド スレッドの変更が完了myMap
しているため、UiThread が安全にアクセスできることがわかっている場合、記述した内容はすでにスレッドセーフです。