"后续读取"在volatile变量的上下文中意味着什么?

Tri*_*tos 13 java multithreading cpu-architecture

Java 内存可见性文档说:

在每次后续读取同一字段之前,会发生对易失性字段的写入.

我很困惑多线程背景下的后续意义.这句话是否意味着所有处理器和内核都有一些全局时钟.那么例如我在某个线程的循环c1中为变量赋值,然后第二个线程能够在后续循环c1 + 1中看到该值?

Pet*_*des 8

听起来像它说它在线程之间提供无锁的获取/释放内存排序语义.请参阅Jeff Preshing撰写的解释该概念的文章(主要针对C++,但该文章的主要观点是语言中立和关于概念.)

事实上,Java volatile提供了顺序一致性,而不仅仅是acq/rel.但是,没有实际的锁定.请参阅Jeff Preshing的文章,了解为什么命名符合您使用锁定所做的操作.)


如果读者看到你写的值,那么它就知道在写之前生产者线程中的所有内容都已经发生了.

此排序保证仅在与单个线程的排序保证相结合时才有用.

例如

int data[100];
volatile bool data_ready = false;
Run Code Online (Sandbox Code Playgroud)

制片人:

data[0..99] = stuff;
 // release store keeps previous ops above this line
data_ready = true;
Run Code Online (Sandbox Code Playgroud)

消费者:

while(!data_ready){}     // spin until we see the write
// acquire-load keeps later ops below this line
int tmp = data[99];      // gets the value from the producer
Run Code Online (Sandbox Code Playgroud)

如果data_ready不是volatile,那么读它就不会在两个线程之间建立一个先发生过的关系.

您不必拥有一个spinloop,您可以从a读取序列号或数组索引volatile int,然后阅读data[i].


我不太了解Java.我认为volatile实际上给你顺序一致性,而不仅仅是发布/获取.顺序释放存储不允许在以后加载时重新排序,因此在典型的硬件上,它需要昂贵的内存屏障,以确保在允许任何后续加载执行之前刷新本地核心的存储缓冲区.

Volatile Vs Atomic解释了有关订购的更多信息volatile.

Java的volatile只是一个排序关键字; 它等同于C11 _AtomicC++ 11std::atomic<T>,它们也为您提供原子RMW操作.在Java中,volatile_var++原子增量,它一个单独的加载和存储,等volatile_var = volatile_var + 1.在Java中,您需要一个类AtomicInteger来获取原子RMW.

请注意,C/C++ volatile并不意味着原子性或排序; 它只告诉编译器假设该值可以异步修改.除了最简单的情况之外,这只是您无需编写任何内容所需的一小部分内容.

  • 这是正确的答案 - 在此上下文中的_subsequent_意味着"读取新值的读取",以便不调用全局时钟或类似的东西.从理论上讲,这可以使写入无限延迟,因为不能保证任何读取很快就会看到这个值 - 但实际上在所有有趣的架构中,写入通常会很快变得可见(通常是单位数纳秒,典型的最差)情况可能是几百纳秒). (3认同)
  • @Gray:谢谢,我没想到初学者可能会有这种混乱.获取/释放是这种内存排序语义的标准术语,但我添加了一些词来表明它是无锁内存排序,*不是*获取锁定.(Jeff Preshing的文章已经完全解释了这一点,但在答案中把它放在这里并不是一件坏事.) (2认同)