コメントで私が話していたことのより具体的な例を挙げると役立つかもしれません. 私がこのようなことをするとしましょう:
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に見えます。ああ、マルチスレッドの楽しさ!CHMHoldernull
mapがマークされている場合final、user2864740 が参照した JLS ビットが適用されます。つまり、threadB が threadA と同じインスタンスを認識した場合 (これもそうではない可能性があります)、実行したmap = new...アクションも認識threadAします。つまり、非nullCHM インスタンスを認識します。それが確認されると、CHM の内部スレッドの安全性は、安全なアクセスを確保するのに十分になります。