1. The volatile
keyword ensures the visibility of variable value changes
For this point, we need to understand what variable values are in Java. For primitive type variables, the variable value is the assigned numerical value, for example, int a = 1
, then 1 is the variable value of the primitive type variable a
. For reference type variables, the variable value is the address in the stack, for example, Object a = new Object()
, then 0x11111111 is the variable value of variable a
.
In summary, for primitive type variables, assigning a new value to them changes their variable value, for example, a = 2
; and for reference type variables, modifying their address changes their variable value, for example, a = new Object()
.
2. Array types ensure the visibility of internal elements
volatile int[] a = new int[4]
actually, each element a[0]
, a[1]
, a[2]
, and a[3]
in the array has visibility, and for determining their visibility, you can refer to the first point (because each element in the array can be seen as a variable).
3. The visibility of new variables assigned to volatile
variables cannot be guaranteed
volatile Object a = new Object(); Object b = a;
In this case, volatile
cannot guarantee the visibility of variable b
.
In ConcurrentHashMap
and CopyOnWriteArrayList
, we can see the difference:
CopyOnWriteArrayList
:
In the first image, a
is actually the array itself, therefore it has visibility, and directly using a[index]
can safely retrieve the value.
ConcurrentHashMap
:
In the second image, we can see that table
is assigned to a new variable tab
, even though table
itself is marked as volatile
, the new variable tab
does not have visibility, therefore we need to use getObjectVolatile
from Unsafe
to safely retrieve the value.