Edw*_*ard 4 java volatile synchronized java-memory-model
在《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;
}
}
Run Code Online (Sandbox Code Playgroud)
背景线程不会在一秒后停止。因为JVM、HotSpot服务器VM中的提升、优化都是如此。
您可以在以下主题中查看这一点:
为什么 HotSpot 将使用提升来优化以下内容?。
优化过程是这样的:
if (!done)
while (true)
i++;
Run Code Online (Sandbox Code Playgroud)
有两种方法可以解决该问题。
private static volatile boolean stopRequested;
Run Code Online (Sandbox Code Playgroud)
易失性的作用是
——禁止提升
——它保证任何读取该字段的线程都会看到最近写入的值
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();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码就在Effective Java一书中,相当于用来volatile装饰stopRequested.
private static boolean stopRequested() {
return stopRequested;
}
Run Code Online (Sandbox Code Playgroud)
如果此方法省略关键字synchronized,则该程序无法正常运行。
我认为当方法省略关键字时,此更改会导致提升synchronized。
是对的吗?
为了清楚地理解为什么会发生这种情况,您需要了解更深层次上发生的事情。(这基本上是对所谓的“发生之前”关系的解释,我希望使用一种对读者来说更容易理解的语言)。
通常变量存在于 RAM 存储器中。当线程需要使用它们时,它会从 RAM 中取出它们并将它们放入缓存中,以便在需要之前可以尽快访问它们。
使用volatile强制线程直接从 RAM 内存读取和写入变量。因此,当许多线程使用相同的volatile变量时,它们都会看到 RAM 内存中存在的最后一个版本,而不是缓存中可能存在的旧副本。
当线程进入synchronized块时,它需要控制监视器变量。所有其他线程都会等待,直到第一个线程退出块synchronized。为了确保所有线程都可以看到相同的修改,同步块中使用的所有变量都直接从 RAM内存而不是从缓存副本读取和写入。
stopRequested因此,如果您尝试在没有synchronized方法或没有关键字的情况下读取变量,volatile您可以读取缓存中存在的可能的旧副本。
要解决这个问题,您需要确保:
volatile变量synchronized块。使用方法
private static boolean stopRequested() {
return stopRequested;
}
Run Code Online (Sandbox Code Playgroud)
没有synchronized关键字,when stopRequestedis 并不意味着您可以从无效的缓存副本中volatile读取 的值。stopRequested
| 归档时间: |
|
| 查看次数: |
1095 次 |
| 最近记录: |