王有志,一个分享硬核Java技术的互金摸鱼侠
加入Java人的提桶跑路群:共同富裕的Java人
今天是《面霸的自我修养》第4篇文章,我们一起来看看面试中会问到哪些关于volatile的问题吧。
数据来源:
- 大部分来自于各机构(Java之父,Java继父,某灵,某泡,某客)以及各博主整理文档;
- 小部分来自于我以及身边朋友的实际经历,题目上会做出标识,并注明面试公司。
叠“BUFF”:
- 八股文通常出现在面试的第一二轮,是“敲门砖”,但仅仅掌握八股文并不能帮助你拿下Offer;
- 由于本人水平有限,文中难免出现错误,还请大家以批评指正为主,尽量不要喷~~
- 本文及历史文章已经完成PDF文档的制作,提取关键字【面霸的自我修养】。
理论篇
指令重排
:::info
难易程度:🔥🔥🔥
:::
:::warning
重要程度:🔥🔥🔥
:::
:::success
面试公司:无
:::
指令重排是一种优化技术,通过指令乱序执行(Out Of Order Execution,简称OoOE或OOE)提高处理器的执行效率和性能。
以下内容摘自维基百科:
在计算机工程领域,乱序执行(错序执行,英语:out-of-order execution,简称OoOE或OOE)是一种应用在高性能微处理器中来利用指令周期以避免特定类型的延迟消耗的范式。在这种范式中,处理器根据输入数据的可用性确定执行指令的顺序,而不是根据程序的原始数据决定。在这种方式下,可以避免因为获取下一条程序指令所引起的处理器等待,取而代之的处理下一条可以立即执行的指令。
指令重排的基础建立在保证当线程环境下语义准确性的前提下,而不能保证多线程环境下的语义。
内存屏障
:::info
难易程度:🔥🔥🔥🔥🔥
:::
:::warning
重要程度:🔥🔥🔥
:::
:::success
面试公司:无
:::
内存屏障(Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步指令,它使CPU或编译器进行操作时严格按照一定的顺序执行,即保证内存屏障前后的指令不会因为指令重排而导致乱序执行。
JVM中定义了7种屏障:
class OrderAccess : private Atomic {
public:static void loadload();static void storestore();static void loadstore();static void storeload();static void acquire();static void release();static void fence();
}
其中最重要的是4种基本的内存屏障:
- LoadLoad,指令:
Load1; LoadLoad; Load2
。确保Load1在Load2及之后的读操作前完成读操作,Load1前的Load指令不能重排序到Load2及之后的读操作后; - StoreStore,指令:
Store1; StoreStore; Store2
。确保Store1在Store2及之后的写操作前完成写操作,且Stroe1写操作的结果对Store2可见,Store1前的Store指令不能重排序到Store2及之后的写操作后; - LoadStore,指令:
Load1; LoadStore; Store2
。确保Load1在Store2及之后的写操作前完成读操作,Load1前的Load指令不能重排序到Store2及之后的写操作后; - StoreLoad:指令:
Store1; StoreLoad; Load2
。确保Store1在Load2及之后的Load指令前完成写操作,Store1前的Store指令不能重排序到Load2及之后的Load指令后。
至于acquire,release和fence,我们通过一张表格来表示它们与4种基本内存屏障的对应关系:
约束 | |
---|---|
fence | LoadLoad |
StoreStore | |
LoadStore | |
StoreLoad | |
release | LoadStore |
StoreStore | |
acquire | LoadLoad |
LoadStore |
Tips:
- 内存屏障的定义位于orderAccess.hpp中,强烈建议阅读注释中的“Memory Access Ordering Model”;
- 重点理解4种基本内存屏障实现的功能即可,JVM源码对的部分了解即可,
也别往下卷了,啥时候是个头啊; - Java中定义的内存屏障屏蔽不同操作系统间内存屏障的差异,使得不同的操作系统表现出一致的语义。
原理篇
🔥volatile是什么?
:::info
难易程度:🔥🔥🔥
:::
:::warning
重要程度:🔥🔥🔥
:::
:::success
面试公司:腾讯
:::
volatile是Java提供的关键字,可以用来修饰成员变量。volatile提供了两个能力:
- 保证被修饰变量在多线程环境下的可见性
- 禁止被修饰变量的指令重排
volatile
保证可见性的例子
private static volatile boolean flag = true;public static void main(String[] args) throws InterruptedException {new Thread