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;
    }
}
背景线程不会在一秒后停止。因为JVM、HotSpot服务器VM中的提升、优化都是如此。
您可以在以下主题中查看这一点:
为什么 HotSpot 将使用提升来优化以下内容?。  
优化过程是这样的:
if (!done)
    while (true)
        i++;
有两种方法可以解决该问题。
private static volatile boolean stopRequested;
易失性的作用是
——禁止提升
——它保证任何读取该字段的线程都会看到最近写入的值
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块时,它需要控制监视器变量。所有其他线程都会等待,直到第一个线程退出块synchronized。为了确保所有线程都可以看到相同的修改,同步块中使用的所有变量都直接从 RAM内存而不是从缓存副本读取和写入。
stopRequested因此,如果您尝试在没有synchronized方法或没有关键字的情况下读取变量,volatile您可以读取缓存中存在的可能的旧副本。
要解决这个问题,您需要确保:
volatile变量synchronized块。使用方法
private static boolean stopRequested() {
   return stopRequested;
}
没有synchronized关键字,when stopRequestedis 并不意味着您可以从无效的缓存副本中volatile读取 的值。stopRequested
| 归档时间: | 
 | 
| 查看次数: | 1095 次 | 
| 最近记录: |