【问题标题】:how/why does writing to a volatile variable cause flushing of other variables?如何/为什么写入 volatile 变量会导致其他变量的刷新?
【发布时间】:2018-03-27 21:18:41
【问题描述】:

我正在阅读 Java 中的并发,包括 volatile 变量,例如这里:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

下面这段话很有意思,但我还不太明白:

实际上,因为新的内存模型对 重新排序[通过例如处理器效率] 易失性字段访问与其他字段访问, volatile 与否,线程 A 在写入时可见的任何内容 到 volatile 字段 f 在读取 f 时对线程 B 可见。

我已经明白volatile 变量不能缓存在寄存器中,因此任何线程的任何写入都将立即被所有其他线程看到。同样根据这个 (https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html) 对 volatile 变量的读取和写入是原子的(不确定这是否会包括像 x++ 这样的东西,但这与这篇文章无关)。

但我提供的报价似乎暗示了除此之外的一些东西。它表示线程 A 可见的 任何东西 现在对线程 B 可见。

所以只是为了确保我有这个权利,这是否意味着当一个线程写入一个 volatile 变量时,它会将其整个处理器寄存器完全转储到主内存?您能否提供更多关于如何以及为什么会发生这种情况的背景信息?它也可能有助于将其与同步进行比较/对比(它遵循类似的机制还是不同的机制?)。此外,示例永远不会对像这样复杂的事情造成伤害:)。

【问题讨论】:

  • 您是想了解规范还是实现?
  • 我想你可能会说我正在尝试理解规范,尽管以示例的方式提及规范实现的不同方式并没有什么坏处。
  • 据我了解,如果 ThreadA 在 F 发布,而 ThreadB 在读取 volatile 后从 F 读取,则其他变量变为可见。
  • 就规范而言,您的理解是正确的。在写入 volatile 变量之前,线程中的所有写入在读取同一变量后对另一个线程可见。同步具有类似的效果。请参阅Oracle tutorialJCIP 了解更多信息。

标签: java multithreading


【解决方案1】:

在 x64 上,JIT 生成了一条带有读或写屏障的指令。实现是在硬件中,而不是在软件中。

这是否意味着当线程写入 volatile 变量时,它会将其整个处理器寄存器完全转储到主内存?

不,只有写入内存的数据会被刷新。不注册。

您能否提供更多关于这种情况发生的方式和原因的背景信息?

CPU 使用 L2 缓存一致性协议来实现这一点(取决于 CPU)

注意:在单cpu系统上,它不需要做任何事情。

这也有助于将其与同步进行比较/对比(它遵循类似的机制还是不同的机制?)。

它使用相同的指令。

此外,示例永远不会对像这样复杂的事情造成伤害:)。

当你阅读时,它会增加一个阅读障碍。

当你写的时候,它会增加一个写屏障。

然后,CPU 会确保存储在 L1 和 L2 缓存中的数据与其他 CPU 适当同步。

【讨论】:

  • 我的问题是否正确?:“据我了解,如果 ThreadA 在 F 发布,而 ThreadB 在读取 volatile 后从 F 读取,其他变量变得可见。”
【解决方案2】:

是的,你是对的。这正是发生的事情。这与通过所谓的内存屏障有关。更多细节在这里:https://dzone.com/articles/memory-barriersfences

【讨论】:

    猜你喜欢
    • 2016-12-12
    • 2021-07-25
    • 1970-01-01
    • 2021-04-01
    • 2019-06-02
    • 2012-03-08
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多