gpt4 book ai didi

java - synchronized 和 volatile 在 Java 内存模型中如何工作?

转载 作者:搜寻专家 更新时间:2023-11-01 02:59:29 24 4
gpt4 key购买 nike

在《Effective Java》一书中:

// Broken! - How long would you expect this program to run?
public class StopThread {

private static boolean stopRequested;

public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();

TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}

backgroundThread 不会在一秒后停止。因为 提升,JVM 中的优化,HotSpot 服务器虚拟机。

您可以在以下主题中查看:
Why HotSpot will optimize the following using hoisting? .

优化是这样的:

if (!done)
while (true)
i++;

有两种方法可以解决这个问题。

1。使用volatile

private static volatile boolean stopRequested;

volatile的作用是
- 禁止吊装
- 它保证任何读取该字段的线程都将看到最近写入的值

2。使用同步

public class StopThread {

private static boolean stopRequested;

private static synchronized void requestStop() {
stopRequested = true;
}

private static synchronized boolean stopRequested() {
return stopRequested;
}

public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();

TimeUnit.SECONDS.sleep(1);
requestStop();
}
}

上面的代码就在Effective Java一书中,相当于用volatile修饰stopRequested

private static boolean stopRequested() {
return stopRequested;
}

如果此方法省略 synchronized 关键字,则此程序无法正常运行。
我认为当方法省略 synchronized 关键字时,此更改会导致提升
是吗?

最佳答案

要清楚地理解为什么会发生这种情况,您需要了解更深层次的情况。 (这基本上是对所谓的先行关系的解释,我希望使用的语言对读者来说更容易理解)。

通常变量存在于 RAM 内存中。当一个线程需要使用它们时,它会从 RAM 中取出它们并将它们放入缓存中,以便它可以在需要时尽快访问它们。

使用 volatile 强制线程直接从 RAM 内存读取和写入变量。因此,当许多线程使用相同的 volatile 变量时,所有线程都看到 RAM 内存中存在的最后一个版本,而不是缓存中可能的旧副本。

当一个线程进入一个synchronized block 时,它需要控制一个监视器变量。所有其他线程等待,直到第一个线程从 synchronized block 中退出。为确保所有线程都能看到相同的修改,同步块(synchronized block)中使用的所有变量都直接从 RAM 内存而不是缓存副本读取和写入。

因此,如果您尝试在没有synchronized 方法或没有volatile 关键字的情况下读取变量stopRequested,您可以读取一个可能的旧副本它存在于缓存中。

要解决这个问题,您需要确保:

  • 所有线程都使用volatile变量
  • 或者所有访问这些变量的线程都在使用一个synchronized block 。

使用方法

private static boolean stopRequested() {
return stopRequested;
}

没有 synchronized 关键字并且当 stopRequested 不是 volatile 时意味着您可以读取 stopRequested 的值来自无效的缓存副本。

关于java - synchronized 和 volatile 在 Java 内存模型中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39929963/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com