コメントで私が話していたことのより具体的な例を挙げると役立つかもしれません. 私がこのようなことをするとしましょう:
public class CHMHolder {
private /*non-final*/ CHMHolder instance;
public static CHMHolder getInstance() {
if (instance == null) {
instance = new CHMHolder();
}
return instance;
}
private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
public ConcurrentHashMap<String, String> getMap() {
return map;
}
}
さて、これはさまざまな理由からスレッドセーフではありません! しかし、threadA が のnull
値を認識しinstance
て をインスタンス化しCHMHolder
、threadB が偶然にも同じCHMHolder
インスタンスを認識したとします (同期がないため、これは保証されません)。threadB は non- を見ていると思いますよnull
CHMHolder.map
ね?map = new ...
threadAと threadB の間に正式な事前発生エッジがないため、そうではない可能性がありreturn map
ます。
これが実際に意味することは、ようなものCHMHolder.getInstance().getMap().isEmpty()
が をスローする可能性があるということですNullPointerException
。これは紛らわしいでしょう — 結局のところ、getInstance
それは常に non- を返す必要があり、常に non- mapを持つ必要があるようnull
CHMHolder
に見えます。ああ、マルチスレッドの楽しさ!CHMHolder
null
map
がマークされている場合final
、user2864740 が参照した JLS ビットが適用されます。つまり、threadB が threadA と同じインスタンスを認識した場合 (これもそうではない可能性があります)、実行したmap = new...
アクションも認識threadA
します。つまり、非null
CHM インスタンスを認識します。それが確認されると、CHM の内部スレッドの安全性は、安全なアクセスを確保するのに十分になります。