Volatile全方位解析
volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~
1.volatile的用法
2.vlatile变量的作用
3.现代计算机的内存模型(计算机模型,总线,MESI协议,嗅探技术)
4.Java内存模型(JMM)
5.并发编程的3个特性(原子性、可见性、有序性、happen-before、as-if-serial、指令重排)
6.volatile的底层原理(如何保证可见性,如何保证指令重排,内存屏障)
7.volatile的典型场景(状态标志,DCL单例模式)
8.volatile常见面试题&&答案解析
「github 地址」
❝https://github.com/whx123/JavaHome❞
1.volatile的用法
volatile关键字是Java虚拟机提供的的「最轻量级的同步机制」,它作为一个修饰符出现,用来「修饰变量」,但是这里不包括局部变量哦。我们来看个demo吧,代码如下:
/**
-
@Author 捡田螺的小男孩
-
@Date 2020/08/02
-
@Desc volatile的可见性探索
*/
public class VolatileTest {public static void main(String[] args) throws InterruptedException {
Task task = new Task();Thread t1 = new Thread(task, "线程t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); System.out.println("开始通知线程停止"); task.stop = true; //修改stop变量值。 } catch (InterruptedException e) { e.printStackTrace(); } } }, "线程t2"); t1.start(); //开启线程t1 t2.start(); //开启线程t2 Thread.sleep(1000);
}
}
class Task implements Runnable {
boolean stop = false;
int i = 0;
@Override
public void run() {
long s = System.currentTimeMillis();
while (!stop) {
i++;
}
System.out.println("线程退出" + (System.currentTimeMillis() - s));
}
}
「运行结果:」
可以发现线程t2,虽然把stop设置为true了,但是线程t1对t2的「stop变量视而不可见」,因此,它一直在死循环running中。如果给变量stop加上volatile修饰,线程t1是可以停下来的,运行结果如下:
volatile boolean stop = false;
- vlatile修饰变量的作用
从以上例子,我们可以发现变量stop,加了vlatile修饰之后,线程t1对stop就可见了。其实,vlatile的作用就是:「保证变量对所有线程可见性」。当然,vlatile还有个作用就是,「禁止指令重排」,但是它「不保证原子性」。
所以当面试官问你「volatile的作用或者特性」,都可以这么回答:
保证变量对所有线程可见性;
禁止指令重排序
不保证原子性
- 现代计算机的内存模型(计算机模型,MESI协议,嗅探技术,总线)
为了更好理解volatile,先回顾一下计算机的内存模型与JMM(Java内存模型)吧~
计算机模型计算机执行程序时,指令是由CPU处理器执行的,而打交道的数据是在主内存当中的。
由于计算机的存储设备与处理器的运算速度有几个数量级的差距,总不能每次CPU执行完指令,然后等主内存慢悠悠存取数据吧, 所以现代计算机系统加入一层读写速度接近处理器运算速度的高速缓存(Cache),以作为来作为内存与处理器之间的缓冲。
在多路处理器系统中,每个处理器都有自己的高速缓存,而它们共享同一主内存。「计算机抽象内存模型」如下:
程序执行时,把需要用到的数据,从主内存拷贝一份到高速缓存。
CPU处理器计算时,从它的高速缓存中读取,把计算完的数据写入高速缓存。
当程序运算结束,把高速缓存的数据刷新会主内存。
随着科