1、volatile は変数値の変更の可視性を保証します
この点について、私たちは Java で変数値とは何かを理解する必要があります。基本型の変数に対して、変数値はそれに与えられた値です。例えば、int a=1 の場合、1 は基本型変数 a の変数値です。一方、参照型の変数に対して、変数値はスタック上のアドレスです。例えば、Object a=new Object () の場合、0x11111111 は変数 a の変数値です。
まとめると、基本型の変数に対しては、新しい値を割り当てることで変数値が変更されます。例えば、a=2 とすると変数値が変更されます。一方、参照型の変数に対しては、アドレスを変更することで変数値が変更されます。例えば、a=new Object () とすると変数値が変更されます。
2、配列型は内部の要素の可視性を保証します
volatile int [] a = new int [4] とすると、配列の各要素 a [0]、a [1]、a [2]、a [3] は実際には可視性を持っています。その可視性の判断は、第 1 条を参照することができます(配列の各要素は変数と見なすことができるため)。
3、volatile 変数に代入された新しい変数は可視性を保証できません
volatile Object a = new Object();
Object b = a;
ここで volatile は変数 b の可視性を保証できません。
concurrentHashMap や CopyOnWriteArrayList では異なることがわかります:
CopyOnWriteArrayList:
第 1 の図では、実際には a は array そのものであり、したがって可視性を持っています。a [index] を直接使用して値を安全に取得できます。
concurrentHashMap:
第 2 の図からわかるように、table は新しい変数 tab に割り当てられています。table 自体は volatile 修飾されていますが、新しい変数 tab は可視性を持っていません。したがって、値を安全に取得するためには、Unsafe クラスの getObjectVolatile を使用する必要があります。