【问题标题】:Is JVM allowed to reorder instructions around AtomicInteger callsJVM 是否允许围绕 AtomicInteger 调用重新排序指令
【发布时间】:2015-12-22 06:36:18
【问题描述】:

是否可以假设(AtomicInteger a).addAndGet(-1) 之前的代码将始终在此调用之前执行,即 JVM 将不会重新排序 addAndGet 调用周围的指令?

如果是,是否可以假设检查同一AtomicInteger 实例(例如if (a.compareAndSet(0, -1)))状态的其他线程将看到第一个线程在addAndGet 调用之前更改的所有内容?

【问题讨论】:

  • 我相信你只能依赖 set 发生之前的事实——在获取特定的 AtomicInteger 之前。
  • 要吹毛求疵,您永远无法保证执行某事的时间,而是保证可观察到的效果。但这实际上是你感兴趣的。你不应该忽略在if(a.compareAndSet(…)) 内,你只会保证看到线程所做的更改,这些线程将值转换为期望值。因此,您必须确保没有多种方法可以达到该值……
  • @Holger,在这种情况下有什么帮助?我必须看到所有线程的变化,这减少了a 的值,最后一个使其为零的线程必须使用从所有线程收集的数据。
  • 只要有恰好个线程将值减小到零,就没有问题。您不得拥有可以再次增加数量的线程(在检测到零之前)并且不得超过必要的线程数。例如。如果你从a=5 开始,并且有六个递减线程,当达到零时,一个线程可能不同步,你不知道是哪一个。但如果你正好有五个递减线程,你就知道所有线程都必须通过障碍......

标签: java multithreading concurrency jvm atomicinteger


【解决方案1】:

假设之前的代码是否安全(AtomicInteger a).addAndGet(-1) 将始终在此调用之前执行,即 JVM 不会对 addAndGet 调用周围的指令重新排序?

是的,没错。 addAndGet 将发出一个 volatile 存储(或类似的),因此其他加载和存储不能在它下面重新排序。

编辑:感谢 Soitrios 链接https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html,这表明已经为您建立了订购。

  • get 具有读取 volatile 变量的记忆效应。
  • set 具有写入(分配)易失性变量的记忆效应。
  • compareAndSet 和所有其他读取和更新操作(例如 getAndIncrement)具有读取和写入 volatile 变量的记忆效应。

【讨论】:

  • 不仅 JVM 被阻止,CPU 也被阻止。即 CPU 也可以重新排序指令的执行。
  • @John Vint,您是否同意上面关于“在if(a.compareAndSet(…)) 内的@Holger 评论,您只能保证看到将值变为预期值的线程所做的更改价值”?
  • 是的,我同意这种说法。由于我们不能说失败的线程成功写入,因此它永远不会发出易失性存储。因此,该线程的写入和后续线程的读取之间没有同步。
猜你喜欢
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2019-05-10
  • 2016-06-04
  • 2021-01-16
相关资源
最近更新 更多