-
volatile关键字的理解
首先volatile只能修饰实例变量或者类变量,不能修饰方法、局部变量、方法参数等。并发的三个至关重要的特性,原子性、可见性、有序性,volatile只能保证前面的两个特性,所以使用volatile关键字要在合适的业务场景。
一、volitile的可见性
多线程的可见性,简单来说是指多个线程共享的变量修改以后,各个线程都能看到变量已经修改了,并且从主内存中拷贝变量改变后的值。
public class TestVisibility { private static boolean stopFlag; public static void main(String[] args)throws InterruptedException{ Thread loop = new Thread(()->{ int i=0; while(!stopFlag){ i++; } System.out.println("Thread is stopped and evaluated result is:"+i); }); loop.start(); TimeUnit.SECONDS.sleep(1); stopFlag = true; } }
上面的TestVisibility的测试类,预计期望1秒后程序会停止并打印出计算结果,但运行结果是它会一直运行没有停止。
变量stopFlag是基本数据类型所以线程操作是原子的,单个原子操作是线程安全的,但是只能保证原子性,对其他线程是不可见的,在主线程sleep一段时间后 stopFlag 的修改子线程loop没有感知到,循环会一直继续下去。
要使loop线程在sleep后正常退出,可以stopFlag前加上volatile关键字就可以了,因为volatile是可以保证可见性的。
二、有序性
有序性:是指按照代码的先后的执行程序。但是由于Java编译器的优化,代码的执行顺序不一定是你编写后代码的顺序。
int x= 0 ; int y= 0 ; x++; y= 20 |
上面的代码执行可能是按照从上至下编写的顺序执行的,但在jvm执行的时候不一定是这样的顺序,有可能 y=20 在x++的前面执行,这就是指令的重排序。
volatile可以保证有序性。volatile对修饰的变量前后无依赖关系的指令可以随便怎么排序:
1 int x=0; 2 int y=0; 3 volatile z=20; 4 x++; 5 y=20
上面第3行的前后的逻辑不管怎么排列,只要到第3行执行的时候x=0 y=0就可以。对变量z多个线程进行操作,volatile的有序性强制限制修改变量的线程要在读的线程之前。
来源:https://www.cnblogs.com/niezhichao/p/14233104.html