1.volatile关键字的作用
-
禁止jit编译器优化
变量被volatile修饰后,在程序中所有引用该变量的地方会禁止jit编译器对这一块代码段进行优化。那么禁止了jit编译器优化功能对程序有什么好处呢?jit编译器有时候是会曲解程序的语义的,在多线程环境下可能会改变代码原本的功能,其中一个例子就是某些共享变量(如static修饰的静态变量)原本应该是共享的,在jit编译器优化之后反而对一些读线程不可见了。在这种场景下我们就需要禁止jit编译器的优化,在一些共享变量前使用volatile进行修饰,避免jit编译器曲解程序语义从而进行优化。 -
禁止指令重排序
指令重排序其实也算是编译器优化的一个例子,所谓指令重排序就是指程序中的某行代码的执行顺序可能会更改,比它上一行代码先执行或者比它的下一行代码后执行,但是我们如果想要避免这种情况,让所有代码都顺序执行,那么就需要使用volatile关键字。volatile关键字做的主要的事情是将一个共享变量的读和写增加一个屏障,当需要读取共享变量时,会在读变量的代码的下方增加一个屏障,所有下方代码都不会跑到读变量语句的上方,当需要写共享变量时,会在写变量的上方增加屏障,所有上方代码不会跑到写变量语句的下方。
2.使用volatile关键字的技巧
- 在多线程环境下如果希望一个线程修改了某个共享变量能够实时地让其他线程也知道的话,就需要使用volatile修饰这个共享变量
- 如果是为了防止指令重排序的话,因为在实际场景中我们需要的共享变量非常多,volatile关键字要是加的太多是会造成性能问题的(因为禁止了jit优化),所以一个折中的方法就是我们尽量将volatile关键字修饰的共享变量,在对其读操作时放到最上方,在对其写操作时放到最下方(原因可以通过volatile形成的屏障来解释)