发生在直接的ByteBuffer之前

Phi*_*all 11 java multithreading nio happens-before off-heap

我在一个线程中有一个直接的ByteBuffer(off-heap),并使用JMM给我的一种机制安全地将它发布到另一个线程.之前发生的关系是否扩展到ByteBuffer包装的本机(堆外)内存?如果不是,我怎样才能安全地将直接ByteBuffer的内容从一个线程发布到另一个线程?

编辑

这不是重复的多个线程可以在Java中看到直接映射的ByteBuffer上的写入吗?因为

  • 我不是在谈论一个mmaped()区域,而是一个普遍的堆外区域
  • 我正在安全地发布ByteBuffer
  • 我不是同时修改ByteBuffer的内容,我只是将它从一个线程变为另一个线程

编辑2

这不是使Java的ByteBuffer线程安全选项的重复我不是试图从两个不同的线程同时修改ByteBuffer.我试图从一个线程转到另一个线程并且在由直接ByteBuffer支持的本机内存区域上的语义之前发生.一旦交接,第一个线程将不再修改或读取ByteBuffer.

Bee*_*ope 3

当然,如果您在 Java 代码中使用和ByteBuffer等 Java 方法来读取和编写,那么您对第一个线程的修改、发布/消费以及最终对第二个线程的后续访问之间的happens-before关系将在预期中应用0方式。毕竟,由“堆外”内存支持的事实只是一个实现细节:它不允许 Java 方法破坏内存模型契约。putgetByteBufferByteBuffer

如果您正在讨论通过 JNI 或其他机制调用的本机代码写入此字节缓冲区,事情就会变得有点模糊。我认为只要您在本机代码中使用普通存储(即,不是非临时存储或任何语义比普通存储弱的东西),您在实践中就会很好。毕竟,JMV 在内部通过相同的机制实现了对堆内存的存储,特别是getandput类型方法将通过正常的加载和存储来实现。发布操作通常涉及某种类型的发布存储,将应用于所有先前的 Java 操作以及本机代码内的存储。

您可以在并发邮件列表上找到一些或多或少与此主题相关的专家讨论。确切的问题是“我可以使用 Java 锁来保护仅由本机代码访问的缓冲区吗”,但潜在的问题几乎是相同的。结论似乎与上面的一致:如果你进行正常的加载并存储到正常的1内存区域,那么你是安全的。如果你想使用较弱的指令,你需要一个栅栏。


0因此,这是一个有点冗长、折磨人的句子,但我想澄清的是,有一整套发生前对必须正确同步才能正常工作:(A)在写入之间第一个线程上的缓冲区和发布存储,(B) 发布存储和消耗负载,(C) 消耗负载以及第二个线程的后续读取或写入。配对(B)纯粹是在爪哇岛,所以遵循常规规则。那么问题主要是关于具有一个“本机”元素的 (A) 和 (C) 是否也可以。

1在这种情况下 ,正常或多或少意味着 Java 使用的相同类型的内存区域,或者至少是一个与 Java 使用的内存类型具有强一致性保证的内存区域。你必须不遗余力地违反这一点,并且因为你正在使用ByteBuffer你已经知道该区域是由 Java 分配的并且必须按正常规则运行(因为 Java 级别的方法需要ByteBuffer以一致的方式工作)至少与内存模型有关)。