提问人:xpt 提问时间:11/15/2023 更新时间:11/15/2023 访问量:42
潜在的 Java 争用条件
Potential Java Race Conditions
问:
试图理解以下说法:
当 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 中,像布尔值这样的原始数据是原子操作。
- 即使读取器线程未能观察到编写器线程在一个循环中所做的更改,它也应该能够在下一个循环中看到更改。
不是这样吗?为什么?因为读取器线程可能永远不会屈服于写入器线程?(如果是这样,我认为它不应该被称为竞争条件,对吧?
答:
2赞
rzwitserloot
11/15/2023
#1
不是这样吗?
不。
每个线程都可以自由地创建任何字段的本地缓存副本(通常,它们会这样做)。除非有理由更新这些缓存,否则 JVM 可能会更新几天,如果它愿意的话(规范没有对 JVM 施加任何要求)。
要强制更新,请使用 、 或 Java 内存规范的 Java 内存模型部分中列出的任何其他 Happens Before 关系。您的代码没有这样的 HB 关系,因此,JVM 永远不必更新。volatile
synchronized
换句话说,一个线程认为是,另一个线程认为是,并且他们继续认为是数小时、数天或永远,或者不 - JVM 规范根本没有指定任何一种方式。shouldFinish
true
false
评论