- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在《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++;
有两种方法可以解决这个问题。
private static volatile boolean stopRequested;
volatile的作用是
- 禁止吊装
- 它保证任何读取该字段的线程都将看到最近写入的值
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/
在 java 中不使用“同步”关键字的情况下,是否有其他方法可以同步类或方法? 谢谢, 马利卡琼·科卡塔努尔 最佳答案 您可能想查看并发包中引入的对 JDK 5 的更改。 http://java.su
第 1 部分: 假设下面这段代码 void method1(){ synchronized (lockObject){ method2(); System.ou
我有一个 REST 服务器和一个在移动设备上运行的客户端应用程序。客户端有一些数据并希望从服务器获取数据更新。如何以 RESTful 方式在单个事务中执行此操作? 假设客户有以下元素: widge
我有一个多线程 Java 应用程序。在一种方法中,需要同步一个 ArrayList。由于 arrayList 不是线程安全的,所以我必须使用同步。问题是 ArrayList 类型的对象不是对象的成员变
我正在阅读 Android 示例中的 BluetoothChatService.java 文件,有一件事特别让我感到困惑。 方法在多个位置访问静态成员,并且定义为同步。 在另一部分中,正在访问同一个静
我知道为了实现线程安全和同步,我们使用同步块(synchronized block)或方法。 但我无法理解声明- “Java 中的同步块(synchronized block)在某些对象上同步 ” 任
在 Scala 中使用 JDBC 的示例中,有以下代码: this.synchronized { if (!driverLoaded) loadDriver() } 为什么this.synchro
abstract class A { protected abstract int isRunning(); public void concreteMethod() { synchr
有谁可以分享一下他们的经验吗?“我们什么时候在同步方法和同步块(synchronized block)之间进行调用”有任何性能问题吗? 最佳答案 When do we make a call to u
这是我之前问题的后续问题,Is this variable being safely accessed by using synchronization? 对于下面的程序, Class SubClas
我目前正在为 N 体问题实现多线程版本的 Barnes-Hut 算法。虽然该算法有效,但它不是很优化,我正在尝试减少我的程序的运行时间。 我已经确保有多个线程可以准确地找到我正在使用的空间的边界,并意
我有这门课: public class MyClass { public MyClass(){} public void actionA(){ synchronized
又是一个关于ArrayList和synchronize的问题。 我只想知道这段代码到底做了什么: ArrayList list = ....; synchronized (list) { if
我可以在另一个同步块(synchronized block)中包含同步块(synchronized block)以同步另一个对象吗? 例子: synchronized(myObjetc1){
public class ObjectCounter { private static long numOfInstances = 0; public ObjectCounter(){
我在某处读到,对于 various reasons 应该避免 synchronized(this) .然而,我遇到的一些值得尊敬的代码在构造函数中使用了以下内容: public SomeClass(C
Java 为同步代码的关键部分提供了一种非常方便的习惯用法: synchronized(someObject) { // do something really important all b
我有一个 WeakReference 的 Collections.synchronizedList,_components; 我写了类似下面的内容,希望编译者会提示: public boolean a
使用下面两个版本的Singleton Classes有什么区别 首先我使用的是synchronized(Singleton.class) 在第二个我使用同步(Obj)//第一种类型 公共(public
我正在查看 DatagramSocket 的源代码,我发现了这个: public void disconnect() { synchronized (this) { if (i
我是一名优秀的程序员,十分优秀!