在多线程编程中,关键挑战之一是确保一个线程所做的更改对其他线程可见。虽然此问题通常与内存可见性相关,但另一个潜在因素是编译器如何处理未显式标记为共享的变量的寄存器缓存(例如,没有
volatile
或同步机制)。
考虑以下 Java 示例:
public class Example {
static boolean run = true;
public static void main(String[] args) {
new Thread(() -> {
run = false; // Producer updates the value
}).start();
while (run) {
// Consumer waits for the update
}
System.out.println("Exited loop.");
}
}
这里,变量
run
用于在两个线程之间进行协调。由于它没有标记为 易失性 或同步的,编译器可能会假设该变量是线程本地的。这就提出了一个有趣的问题:
编译器能否通过将其缓存在 CPU 寄存器中来优化对
run
的访问,避免写入内存?如果是这样,这将是:
这种情况可能符合程序逻辑,但可能会破坏多线程环境中预期的内存可见性保证。
在实践中,现代编译器是否有可能优化变量访问,使值仅保存在寄存器中,完全绕过内存写入?
目标是了解:
感谢您对内存可见性这一微妙方面的详细见解!
一般情况下?绝对地。这就是 C/C++ 中使用
register
关键字的全部原因,甚至更明确地说是弃用 register
关键字——现代编译器将在可能的情况下积极使用寄存器而不是内存(以及堆栈,用于函数调用),尤其是在 x64 中,有很多寄存器可以使用。
具体是在 Java 中吗?我对此表示怀疑。请记住,JVM 会解释代码的大部分,它甚至不会从中生成本机汇编代码。