gpt4 book ai didi

java - 在 Java 中模拟内存屏障以消除 volatile 读取

转载 作者:行者123 更新时间:2023-12-02 13:01:30 24 4
gpt4 key购买 nike

假设我有一个并发访问的字段,并且它被多次读取但很少写入。

public Object myRef = new Object();

假设线程 T1 将每分钟一次将 myRef 设置为另一个值,而其他 N 个线程将连续并发地读取 myRef 数十亿次。我只需要 myRef 最终对所有线程可见。

一个简单的解决方案是使用 AtomicReference 或简单地像这样使用 volatile:

public volatile Object myRef = new Object();

但是,据我所知, volatile 读取确实会产生性能成本。我知道它很小,这更像是我想知道的东西,而不是我真正需要的东西。因此,我们不要关心性能并假设这是一个纯粹的理论问题。

所以问题归结为:有没有办法通过在写入站点执行某些操作来安全地绕过很少写入的引用的 volatile 读取?

经过一番阅读,看起来内存屏障可能正是我所需要的。因此,如果存在这样的构造,我的问题就会得到解决:

  • 调用屏障(同步)
  • 一切都已同步,所有线程都将看到新值。 (在读取站点上没有永久成本,它可能会过时或在缓存同步时产生一次性成本,但之后一切都会回到常规字段获取,直到下一次写入)。

Java 中或一般情况下是否有这样的构造?在这一点上,我不禁想到,如果存在这样的东西,它应该已经被更聪明的人维护这些包合并到原子包中了。 (不成比例的频繁读取与写入可能不是一个需要关心的情况?)所以也许我的想法有问题,这样的构造根本不可能?

我已经看到一些代码示例使用“ volatile ”来实现类似的目的,利用它的发生之前契约(Contract)。有一个单独的同步字段,例如:

public Object myRef = new Object();
public volatile int sync = 0;

在编写线程/站点时:

myRef = new Object();
sync += 1 //volatile write to emulate barrier

我不确定这是否有效,有些人认为这仅适用于 x86 架构。在阅读了 JMS 中的相关部分后,我认为只有当 volatile 写入与需要查看 myRef 新值的线程的 volatile 读取相结合时,它才能保证工作。 (所以不会摆脱 volatile 读取)。

回到我原来的问题;这有可能吗?在Java中可以吗? Java 9 VarHandles 中的新 API 之一可能吗?

最佳答案

所以基本上你想要一个 volatile 的语义而不需要运行时成本。

我认为这是不可能的。

问题在于, volatile 的运行时成本是由于在写入器和读取器代码中实现内存屏障的指令造成的。如果您通过消除读取器的内存障碍来“优化”读取器,那么您将不再保证读取器在实际写入时会看到“很少写入”的新值。

FWIW,某些版本的 sun.misc.Unsafe 类提供显式的 loadFencestoreFencefullFence方法,但我认为使用它们不会比使用 volatile 带来任何性能优势。

<小时/>

假设 ...

您想要的是多处理器系统中的一个处理器能够告诉所有其他处理器:

"Hey! Whatever you are doing, invalidate your memory cache for address XYZ, and do it now."

不幸的是,现代 ISA 不支持这一点。

实际上,每个处理器控制自己的缓存。

关于java - 在 Java 中模拟内存屏障以消除 volatile 读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58336714/

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