请解释 Java 中的指令重排是什么,并说明它产生的背景、具体表现以及可能带来的问题。
考察说明
考查对 Java 内存模型和并发底层机制的理解。
回答思路
- 【回答框架 1】指令重排是编译器和处理器为了提高性能而对指令执行顺序进行的调整,包括编译器重排、处理器指令级并行重排和内存系统重排。在 Java 中,JMM(Java 内存模型)允许这些重排,但规定了 happens-before 规则来约束可见性。
- 【回答框架 2】重排可能导致多线程下的可见性问题,例如一个线程写入的值在另一个线程中可能不可见,因为执行顺序被调整了。典型的例子是双重检查锁中的未正确发布对象问题。
- 【回答框架 3】解决重排带来的问题通常使用 volatile 或 synchronized 等同步机制,它们通过内存屏障来禁止特定类型的重排。Volatile 可以防止其前后的重排,synchronized 则通过互斥保证有序性。
- 【关键点 1】指令重排包括编译器重排、处理器指令级重排和内存系统重排。
- 【关键点 2】JMM 通过 happens-before 规则来约束重排,保证可见性和有序性。
- 【关键点 3】Volatile 关键字通过内存屏障禁止重排,适用于状态标志等场景。
- 【易错点 1】不要认为所有重排都是有害的,单线程下重排不影响语义。
- 【易错点 2】不要忽略 volatile 对重排的限制范围,它只保证引用本身的可见性。
- 【易错点 3】不要混淆重排与指令乱序执行,前者是编译期和运行期的优化。