volatile
看过八股的都知道volatile可以保证有序性和可见性,但其实他还保证了部分原子性
有序性
简单地说就是防止指令重排,保证代码按照程序员的意愿执行
它的实现是通过内存屏障来实现的。硬件层面有Load Barrier读屏障和Store Barrier写屏障 。而jvm层面有
LoadLoad(读读屏障),LoadStore(读写屏障),StoreStore(写写屏障),StoreLoad(读写屏障)。
内存屏障相当于一堵墙,墙两边的指令不能翻墙重排,而墙同侧的可以发生重排
eg:指令1 指令2 | 指令3 指令4
指令2和指令3不可以重排,即强制执行完指令2后才会执行指令3
指令1和指令2可以重排
内存屏障到底是什么?
本质上就是CPU指令
可见性
一个线程修改了volatile变量,这个修改对于其他线程立即可见

因为CPU运算速度要比内存块很多,所以会把主存的值缓存到高速缓存中。而这时线程的高速缓存可能就会
出现和主存不一致的情况。而volatile就可以解决这种情况
当写一个volatile变量时,写操作完成后会多出一条Lock为前缀的汇编指令,这指令在多核处理器下会做两件
事
1.将当前CPU缓存里的值写回主存
2.将其他CPU核的内存置为无效,读取必须去主存读
当读一个volatile变量时,会直接去主存里读
这样就可以保证其变量在多线程下的可见性了
部分原子性
它的原子性体现在赋值层面,在30位的操作系统,cpu只能一次性读写32位的数据,那么对于long类型的,也就只能分为两步,即高32位,低32位。如果在多线程中,一个线程只操作了前部分,而另外一个线程来操作这个变量,这样的话就发生了错误了么。那如果是被volatile修饰就不会发生这个问题。但自增自减就无法保证其原子性,因为这些操作都不是由单条字节码指令组成的
双重检验锁volatile真正的作用?
DCL
1 | public class TestSingleton implements Serializable { |
网上有很多说法说对它是能防止new操作的指令重排序,然后并不是的,new操作分为三步(分配内存,对象初始化,指针指向),而volatile只能保证单个指令的可见性,有序性,原子性,i++这种也是无法保证的。它真正的作用是通过在new操作前加入了store_store屏障,在后加入store_load屏障。保证对INSTANCE的写是要优先于对它的读的,但其new的内部是无法保证有序性的,从而避免了有线程获得还没有初始化的实例