AtomicXXX.lazySet(...)在边缘之前发生

Beg*_*moT 17 java concurrency atomic

AtomicXXX.lazySet(value)方法在大多数JMM推理中使用的前沿边缘是什么意思?javadocs是纯粹的,Sun bug 6275329声明:

语义是保证写入不会与任何先前的写入重新排序,但可以与后续操作重新排序(或者等效地,可能对其他线程不可见),直到发生一些其他易失性写入或同步动作).

但这不是关于HB边缘的推理,所以它让我感到困惑.这是否意味着什么lazySet()语义不能用HB边缘表示?

更新:我会尝试将我的问题具体化.我可以在以下场景中使用普通的volatile字段:

//thread 1: producer
...fill some data structure
myVolatileFlag = 1;

//thread 2: consumer
while(myVolatileFlag!=1){
   //spin-wait
}
...use data structure...
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在消费者中使用"数据结构"是正确的,因为易失性标志写入读取使得HB边缘,从而保证生产者对"数据结构"的所有写入都将完成,并且消费者可以看到.但是如果我在这种情况下使用AtomicInteger.lazySet/get而不是volatile写/读怎么办?

//thread 1: producer
...fill some data structure
myAtomicFlag.lazySet(1);

//thread 2: consumer
while(myAtomicFlag.get()!=1){
   //spin-wait
}
...use data structure...
Run Code Online (Sandbox Code Playgroud)

它仍然是正确的吗?消费者线程中的"数据结构"值可见性真的可以吗?

它不是"来自空中"的问题 - 我在LMAX Disruptor代码中看到了这种方法正好在这种情况下,我不明白如何证明它是正确的......

Ben*_*nes 12

这些lazySet操作不会创建先前发生的边缘,因此不能保证立即可见.这是一个低级优化,只有少数用例,主要是并发数据结构.

将链接列表指针置零的垃圾收集示例没有用户可见的副作用.归零是首选的,因此如果列表中的节点处于不同的代中,则不会强制执行更昂贵的集合来丢弃链接链.lazySet的使用保持了hygenic语义而不会产生易失性写入开销.

另一个例子是使用由锁保护的易失性字段,例如ConcurrentHashMap.这些字段是易失性的,允许无锁读取,但必须在锁定下执行写入以确保严格一致性.由于锁保证发布之前发生的边缘,优化是在写入字段时使用lazySet并在解锁时刷新所有更新.这有助于通过避免不必要的停顿和总线流量来缩短关键部分.

如果你编写并发数据结构,那么这lazySet是一个很好的技巧.它是一种低级优化,因此在性能调优时仅值得考虑.