Java 线程同步方法

Java Thread Synchronized methods

我有以下代码

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

synchronized 是可重入的,获得同步块锁的同一个线程保证如果它仍然拥有锁,它将在下一次尝试获取时保持它,但这没有由于 stopRequested 的更改是在同步块之外进行的并且代码仍然有效,您的代码在实际情况下仍然可能存在竞争条件。

假设在执行 N 时,线程必须因 stopRequested() 满足条件而终止,同时调用 requestStop(),不能保证线程终止在 N+1 因为变量 stopRequested 在两个访问器方法中都不受排他锁保护,变量也没有 volatile 修饰符。这意味着由于竞争条件,您对代码的正确性部分是错误的。

Java 语言规范没有说明该程序是否或何时终止。

如果 方法 requestStop()stopRequested() 同步,您只能确定它会在大约一秒后终止。

如果其中一个不同步,或者两者都不同步,则程序可能会在一秒后终止,或五秒后终止,或者永远不会。它在不同的 Java 运行 时间环境中可能表现不同。它在不同的硬件上可能表现不同。它在一周中的不同日子可能会有不同的表现。

如果两种方法都没有 synchronized,它的行为是未定义的。

Java 并发实践:

的前言中引用了 Dion Almaer 的一句话

Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only "by accident".

这是其中之一。 Java 语言规范不保证更新后的标志可见。如果您不遵守规则,那么关于您的线程是否看到您的标志的新值,您将受制于 JVM 实现。

有些 JVM 实现比其他实现更宽容,有些在设计上更积极地缓存内容。如果它在本地适合您,并不意味着它会在生产环境中工作。

synchronized 块在 Java 中有额外的语义。它们不仅提供代码块的独占执行,而且发出所谓的内存屏障,保证线程之间所有操作结果的可见性。

因此,当您调用 synchronized stopRequested() 方法时,您还使所有更改对当前线程可见。如果您从此方法中删除 synchronized,您也会删除屏障,并且 JVM 不保证您在主线程中设置的标志在后台线程中可见。这就是为什么没有 synchronized.

会出现问题的原因