进行volatile写操作时,不仅会将volatile变量写入共享内存,系统还会将当前线程专属空间中的所有共享变量写入共享内存。
进行volatile读操作时,系统也会一次性将共享内存中所有共享变量读入线程专属空间。
这就意味着,如果普通变量在volatile写操作之前被修改,那么在volatile读操作之后就能正确读到他们。
但是,在volatile写操作之后被修改的普通变量 和 在volatile读操作之前被访问的普通变量 都不具有内存可见性。
原子性指的是一组操作必须一起完成,中途不能被中断。
volatile能确保long、double读写的原子性在Java中的所有类型中,有long、double类型比较特殊,他们占据8字节(64比特),其余类型都小于64比特。在32位操作系统中,CPU一次只能读取/写入32位的数据,因此对于64位的long、double变量的读写会进行两步。在多线程中,若一条线程只写入了long型变量的前32位,紧接着另一条线程读取了这个只有“一半”的变量,从而就读到了一个错误的数据。
为了避免这种情况,需要在用volatile修饰long、double型变量。
在内存可见性与原子性上,volatile就相当于是同步的setter和getter函数。但并不具有volatile的重排序规则,同步块只确保同步块内部的指令不发生重排序,并不确保同步块以外的指令的重排序。
PS1:Java中的byte竟然是字节,bit才是比特(位)。
PS2:char和short-2字节、int和float-4字节、long和double-8字节、byte-1字节