gpt4 book ai didi

Java - 之前发生 - volatile

转载 作者:搜寻专家 更新时间:2023-11-01 01:26:34 25 4
gpt4 key购买 nike

我有下面的代码

class VolatileCount {
volatile int count;
Object lock = new Object();

public void increment() {

synchronized (lock) {
count = count + 1;
}
System.out.print(" " + count);
}

}

如果我从多个线程对同一对象调用 increment(),我会得到以下输出(在您的机器上可能不同)

2 3 2 5 4 8 8 6 11 13 10 9 15 14 12 20 19

看着重复的数字,我认为 happens-before 似乎被打破了,因为考虑到前三个数字 (2 3 2),如果一个线程看到 3 ,增量已经发生并且因为变量是volatile,它的值应该是3或更多,但在任何线程中都不能是2。
但是,这里的打印行似乎已经重新排序,重新排序该行是否正确?我在这里错过了什么?我在 JDK 7 (Eclipse) 上运行

最佳答案

更新

因为你似乎想要解释“2 3 2”的具体情况

  • X 递增 i(现在为 1)
  • Y 递增 i(现在是 2)
  • X 读取 i(X 加载 2)
  • Y 读取 i(Y 加载 2)
  • Y 打印先前加载的值(打印 2)
  • Z 递增 i,读取 i,打印 i(打印 3)
  • X 打印先前加载的值(打印 2)

重点是:System.out.print(""+ count) 不是原子的。在执行 volatile 读取之后和打印值之前,线程可以被抢占。

如果你想防止打印重复的值,你必须在锁执行volatile read:

public void increment() {
int localCount;
synchronized (lock) {
count = count + 1;
localCount = count; // volatile load
}
System.out.print(" " + localCount);
}

但这不会阻止值被乱序打印。为了按顺序打印它们,不重复,您还必须将 print 移到锁中。

旧答案

打印语句在锁外。考虑 System.out.print(""+ count) 中运行的代码。

  • 线程 X 递增 i
  • 线程 X 评估 print 参数并对 count 变量执行 volatile 读取,并加载值 2
  • 线程 X 被线程 Y 抢占,线程 Y 递增 i
  • 线程 Y 加载 i(现在是 3),调用运行完成的 print 方法。
  • 线程 Y 被抢占,线程 X 现在运行 print 直到完成,打印 2。

这会使数字显示乱序,例如“3 2 4”。

某些数字也可能在以下情况下重复:

  • 线程 X 递增 i(现在是 2)
  • 线程 Y 递增 i(现在是 3)
  • 线程 X 打印 i(即 3)
  • 线程 Y 打印 i(即 3)

关于Java - 之前发生 - volatile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21428508/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com