从书中出发#34; Effective java"我有以下着名的代码,从另一个线程停止一个线程
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();
}
}
在那里写入一行" 同步除非读取和写入都没有效果
操作是同步的。"但很明显,如果我们不使用方法synchronized
的{{1}}关键字,代码将正常工作,即它几乎在需要1秒钟。这里更重要的是,如果我们不同步这两种方法,我们(很可能)会因为代码优化而进入无限循环。所以我的问题是: -
1.如果我们不同步“停止请求”,那么在什么情况下会出现问题?方法?虽然在这里如果我们不同步它,程序会按照需要运行,即它几乎在1秒内终止。
2. requestStop
关键字是否强制VM每次都停止优化?
答案 0 :(得分:1)
1.如果我们不同步'stopRequested'方法,怎么会出现问题?
假设一个线程正在写入(更新)字段stopRequested
,现在在第一个线程从requestStop()更新stopRequested
的值之前,另一个线程可以读取{{1}的值}通过调用stopRequested
(如果stopRequested()
不是同步。因此它不会获得更新的值。
2.同步关键字是否强制每次都停止优化? 并非总是如此,从JDK6U23实现的 Escape Analysis 也在其中发挥作用。 同步会创建一个内存屏障,以确保发生在关系之前。即,在同步块之后执行的任何代码块肯定都有更新的值(反映了之前做出的更改)。
语句可以在同步块中执行无序,以提高效率,前提是发生 - 保持良好状态。另一方面,如果确定只能由单个线程访问该块,则JVM可以删除 synchronized块。
答案 1 :(得分:1)
线程对变量的更改不一定会被其他线程立即看到。在此处使用synchronized可确保一个线程的更新对另一个线程可见。
1)其他线程可能无法看到更改。在没有同步或易失性或原子字段的情况下,不能保证其他线程何时会看到变化。
2)synchronized关键字帮助VM决定指令重新排序的限制以及VM可以优化的内容。
在您的计算机上进行测试不一定会显示与使用具有更多处理器的服务器相同的结果。不同的平台可以做更多的优化。因为它适用于您的机器并不一定意味着它没问题。
答案 2 :(得分:1)
1.如果我们不同步“停止请求”,怎么会出现问题?方法?虽然这里如果我们不同步它,程序会按照需要运行,即它几乎在1秒内终止。
如果JVM决定在backgroundThread的run方法中优化代码,那么事情就会出错。可以重新排序对stopRequested()的读取以供JVM优化,因为它可能永远不会再次调用stopRequested()方法。但是现在几乎所有的JVM实现都会处理这个问题,因此无需将stopRequested作为同步,您的代码仍然可以正常运行。另外需要注意的是,如果你没有使stopRequested同步,那么对其他非同步线程可能不会立即看到对stopRequested布尔变量所做的更改。只有当您使用同步时,其他线程才会立即检测到任何更改,因为进入synchronized方法的条目会清除缓存并从内存中加载新数据。在高度并发的系统中,这种即时检测内存变化非常重要
2)synchronized关键字是否强制VM每次停止优化?
同步关键字不会强制VM停止优化,但会使其遵循下面列出的内容。 VM仍然可以进行优化,但它必须处理以下事情。 同步有效地做了以下事情: -
它保证在关系之前发生。如果一个动作发生在另一个动作之前,那么第一个动作在第二个动作之前可见并且在第
它保证了内存可见性,即可以缓存的块内所做的所有修改都会在同步块退出之前立即刷新,这会导致任何其他同步线程立即查看内存更新。这对于高度并发的系统非常重要。
答案 3 :(得分:0)
让stopRequested volatile。然后方法stopRequest不必同步,因为它不会改变任何东西。