1.1.1. Volatile关键字
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
- 保证被volatile修饰的变量对所有线程都是可见的
- 禁止进行指令重排序
1. volatile关键字禁止指令重排序:
当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见,在其后面的操作肯定还没有进行;
在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。
volatile可以保证可见性 有序性,但是无法保证原子性(++的情况)
volatile如何实现内存可见性:通过加入内存屏障和禁止重排序来优化实现的。
- 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令;
- 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令。
2.Volatile的原理和实现机制
观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令
摘自《深入理解Java虚拟机》:
lock前缀指令实际上相当于一个 内存屏障(也成内存栅栏),内存屏障会提供3个功能:
- 确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
- 强制将对缓存的修改操作立即写入主存;
- 如果是写操作,它会导致其他CPU中对应的缓存行无效。
3. synchronized 和 volatile 关键字的作用和区别
3.1作用
- volatile 本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需从主存中读取;
- synchronized则是锁定当前变量,只有当前线程可以访问该变量,其它线程被阻塞住。
3.2区别
volatile 仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
volatile 仅能实现变量的修改可见性,并不能保证原子性;synchronized 则可以保证变量的修改可见性和原子性。
volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
volatile 标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。