volatile 关键字作用是,使系统中所有线程对该关键字修饰的变量共享可见,可以禁止线程的工作内存对volatile修饰的变量进行缓存。
volatile(修饰变量)的作用?
1)保证可见性
volatile本意是不稳定的,易挥发的,也就是说,用它修饰的变量是可变的。
而volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
也就是说,JVM会对线程变量的访问进行优化,这样当多个线程同时与某个对象时交互,就必须要注意到要让线程及时的得到共享成员变量的变化。
而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
2)禁止进行指令重排序
为了使得处理器内部的运算单元尽量被充分利用,提高运算效率,处理器可能会对输入的代码进行排序。但是可能出现下面的情况:
在有逻辑 A与B代码段的情况下,逻辑 A 执行完之后再执行逻辑 B。在处理器乱序执行优化情况下,有可能导致 flag 提前被设置为 true,导致逻辑 B 先于逻辑 A 执行。
这个时候volatile又起到了作用。
当程序执行到 volatile 变量的读操作或者写操作时, 在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行。
在进行指令优化时, 不能将在对 volatile 变量访问的语句放在其后面执行,也不能把 volatile 变量后面的语句放到其前面执行。
(普通的变量仅仅会保证该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证赋值操作的顺序与程序代码中的执行顺序一致)
总结:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。