潜在的 Java 争用条件

Potential Java Race Conditions

提问人:xpt 提问时间:11/15/2023 更新时间:11/15/2023 访问量:42

问:

试图理解以下说法:

当 2 个或更多线程尝试在不同步的情况下访问相同的非最终变量时,就会发生数据争用。不使用同步可能会导致进行对其他线程不可见的更改,因此可以读取过时的数据,这反过来可能会产生无限循环、数据结构损坏或计算不准确等后果。此代码可能会导致无限循环,因为读取器线程可能永远不会观察到编写器线程所做的更改:

class Waiter implements Runnable {
  private boolean shouldFinish;

  void finish() { shouldFinish = true; }

  public void run() {
    long iteration = 0;
    while (!shouldFinish) {
      iteration++;
    }
    System.out.println("Finished after: " + iteration);
  }
}

class DataRace {

  public static void main(String[] args) throws InterruptedException {
    Waiter waiter = new Waiter();
    Thread waiterThread = new Thread(waiter);
    waiterThread.start();

    waiter.finish();
    waiterThread.join();
  }
}

我的想法是,

  • 在 Java Reader/Writer 中,像布尔值这样的原始数据是原子操作。
  • 即使读取器线程未能观察到编写器线程在一个循环中所做的更改,它也应该能够在下一个循环中看到更改。

不是这样吗?为什么?因为读取器线程可能永远不会屈服于写入器线程?(如果是这样,我认为它不应该被称为竞争条件,对吧?

Java 多线程争 用条件

评论


答:

2赞 rzwitserloot 11/15/2023 #1

不是这样吗?

不。

每个线程都可以自由地创建任何字段的本地缓存副本(通常,它们会这样做)。除非有理由更新这些缓存,否则 JVM 可能会更新几天,如果它愿意的话(规范没有对 JVM 施加任何要求)。

要强制更新,请使用 、 或 Java 内存规范的 Java 内存模型部分中列出的任何其他 Happens Before 关系。您的代码没有这样的 HB 关系,因此,JVM 永远不必更新。volatilesynchronized

换句话说,一个线程认为是,另一个线程认为是,并且他们继续认为是数小时、数天或永远,或者不 - JVM 规范根本没有指定任何一种方式。shouldFinishtruefalse