我有以下代码
import java.util.concurrent.*;
public class dsd {
private static boolean stopRequested;
private static 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();
}
}
问题是即使requestStop()
未同步,它仍然有效吗?如果我尝试对stopRequested()
做同样的事情,它就不再起作用了。为什么该变量上的线程并发没有问题?我知道同步使变量出现在其他线程的一致状态中。但是这里变量不同步,似乎没有效果。
答案 0 :(得分:2)
synchronized
是可重入的,获得同步块锁定的同一个线程保证,如果它仍然拥有锁定,它将在下次尝试时保留它,但这并不是这与stopRequested
的更改是在同步块之外进行并且代码仍然有效这一事实有关,您的代码在实际情况下仍可能存在竞争条件。
假设在执行N
时,线程必须在stopRequested()
条件满足时终止,并且在requestStop()
被调用的同时,它不能保证线程终止于N+1
,因为变量stopRequested
在两个访问器方法中都不受独占锁保护,变量也没有volatile
修饰符。这意味着由于竞争条件,你对代码的正确感是部分错误的。
答案 1 :(得分:1)
Java Lanaguage规范没有说明此程序是否或何时终止。
如果两种方法requestStop()
和stopRequested()
同步,您只能确定它会在大约一秒后终止。
如果其中任何一个未同步,或者两者都未同步,则程序可能会在一秒钟后或五秒钟后终止,或者永远不会。它可能在不同的Java运行时环境中表现不同。它可能在不同的硬件上表现不同。它可能在一周的不同日期表现不同。
如果两种方法都不是synchronized
,则其行为未定义。
答案 2 :(得分:1)
Dion Almaer引用了 Java Concurrency in Practice 的前言:
TheServerSide的前编辑Dion Almaer最近写了博客(经过一次痛苦的调试会议,最终揭示了一个线程错误),大多数Java程序都充斥着并发错误,他们只能偶然地工作"#34;。
这是其中之一。 Java语言规范没有做出更新标志可见的承诺。如果您不遵守这些规则,那么您将受制于JVM实施方面,因为您的线程是否会看到您的标志的新值。
有些JVM实现比其他实现更宽容,有些JVM实现了更缓慢的缓存方式。如果它在本地适用于您并不意味着它将在生产中起作用。
答案 3 :(得分:1)
synchronized
块在Java中具有其他语义。它们不仅提供代码块的独占执行,而且还发出所谓的内存屏障,保证线程之间所有操作结果的可见性。
因此,当您调用synchronized stopRequested()
方法时,您还可以对当前线程显示所有更改。如果从此方法中删除synchronized
,则还会删除屏障,并且JVM不保证您在主线程中设置的标志在后台线程中可见。这就是没有synchronized
的问题。