在讲volatile关键字之前我们先了解Java的内存模型,Java内存模型规定所有的变量都是存在主存当中,每个线程都有自己的工作内存。线程对变量的所有操作都必须在自己的工作内存中进行,而不能直接对主存进行操作。各线程间的工作内存互不干扰。
谈一下你对 volatile 关键字的理解?( volatile 的作用是什么?)
答:volatile 是 Java 虚拟机提供的最轻量级的同步机制。当变量被定义成 volatile 之后,具备两种特性:
(1)保证对变量操作的可见性.
(2)禁止指令重排序优化.
注意:不保证原子性
怎么理解原子性,可见性和指令重排?
原子性:程序中的所有操作是不可中断的,要么全部执行成功要么全部执行失败。
可见性:指当多个线程访问同一个变量时,如果其中一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
指令重排:为了提高程序运行效率,可能会对输入指令进行重新排序,即程序中各个语句的执行先后顺序同代码中的顺序不一定一致。(但是它会保证单线程程序最终执行结果和代码顺序执行的结果是一致的)
可见性,指令重排实例:
https://www.cnblogs.com/qdhxhz/p/9179725.html
哪些地方用到过volatile?
1、单例模式(双重检验锁DCL)
菜鸟教程--https://www.runoob.com/design-pattern/singleton-pattern.html
2、读写锁手写缓存
3、CAS JUC包中大量使用volatile
volatile底层的实现机制?
如果把加入volatile关键字的代码和未加入volatile关键字的代码都生成汇编代码,会发现加入volatile关键字的代码会多出一个lock前缀指令。
lock前缀指令实际相当于一个内存屏障,内存屏障提供了以下功能:
1 . 重排序时不能把后面的指令重排序到内存屏障之前的位置
2 . 使得本CPU的Cache写入主存
3 . 写入动作也会引起别的CPU或者别的内核无效化其Cache,相当于让新写入的值对别的线程可见。
Synchronized与volatile区别
(1) synchronized即保证了数据的可见性也保证了原子性,volatile能保证对变量操作的可见性,但不能完全保证原子性。比如,i++ 如果使用 synchronized 修饰是线程安全的,而 volatile 会有线程安全的问题。
(2) volatile只能修饰变量,synchronized可以修饰变量,方法以及代码块。
(3) volatile在多线程中不会存在阻塞问题,synchronized会存在阻塞问题。
(4) volatile解决的是多个线程之间对变量操作的可见性,而synchroized解决的是多个线程之间访问资源的同步性。
参考
面试官必问的8道volatile关键字命题,你答对了吗?
https://blog.csdn.net/l18848956739/article/details/88660353
进行重新排序