volatile三大特性
1) 可见性
2) 不保证原子性
3) 禁止重排序
讨论三大特性之前我们先来谈谈JMM
JMM(java memory model) java内存模型
Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。
简而言之: JMM 可以保证并发编程场景中的原子性、可见性和有序性。
可见性分析
代码演示
public class VolitileTest {
boolean result = true;
volatile boolean volatileResult = true;
@Test
public void test() throws InterruptedException {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
result = false;
} catch (InterruptedException e) {
e.printStackTrace();
}}).start();
while (result) { }
System.out.println("result结果改为false");
}
@Test
public void volatileTest() throws InterruptedException {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
volatileResult = false;
} catch (InterruptedException e) {
e.printStackTrace();
}}).start();
while (volatileResult) { }
System.out.println("volatileResult结果改为false");
}
}
执行结果.png
图解分析.png
volatile不保证原子性分析
代码演示
volatile int a = 0;
@Test
public void testAdd() throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
a++;
}
}).start();
}
TimeUnit.SECONDS.sleep(1);
System.out.println("最后结果: " + a);
}
执行结果.png
图解分析.png
禁止重排序分析
重排序了解
计算机在执行程序的时候, 为了提高性能, 编译器和处理器会对指令进行重排序.
1.单线程环境, 重排序能保证程序的最终结果和顺序执行的结果一致
2.处理器处理重排序必须考虑指令之间的数据依赖性(如b依赖a, 不能将b排序在a之前执行)
3.多线程调度过程中, 由于重排序存在, 两个线程的变量无法保证一致性
重排序.png
图解分析.png
总结
volatile可以理解为轻量级的synchronized, 最适用一个线程写,多个线程读的场合.