Java线程同步方法

时间:2016-09-02 20:18:52

标签: java multithreading synchronized

我有以下代码

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()做同样的事情,它就不再起作用了。为什么该变量上的线程并发没有问题?我知道同步使变量出现在其他线程的一致状态中。但是这里变量不同步,似乎没有效果。

4 个答案:

答案 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的问题。