Java内存模型中的同步和易失性如何工作?
作者:互联网
在“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服务器VM中进行优化.
您可以在以下主题中查看此内容:
Why HotSpot will optimize the following using hoisting?.
优化如下:
if (!done)
while (true)
i++;
有两种方法可以解决问题.
1.使用挥发性
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块退出.为确保所有线程都能看到相同的修改,同步块中使用的所有变量都直接从RAM内存中读取和写入,而不是从高速缓存副本中读取.
因此,如果您尝试在没有synchronized方法或没有volatile关键字的情况下读取变量stopRequested,则可以读取缓存中存在的可能的旧副本.
要解决这个问题,您需要确保:
>所有线程都使用volatile变量
>或访问这些变量的所有线程都使用同步块.
使用方法
private static boolean stopRequested() {
return stopRequested;
}
如果没有synchronized关键字,并且stopRequested不是volatile,则意味着您可以从无效的缓存副本中读取stopRequested的值.
标签:java,synchronized,volatile,java-memory-model 来源: https://codeday.me/bug/20190627/1309681.html