Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java AtomicXXX.lazySet(…)在边之前发生_Java_Concurrency_Atomic - Fatal编程技术网

Java AtomicXXX.lazySet(…)在边之前发生

Java AtomicXXX.lazySet(…)在边之前发生,java,concurrency,atomic,Java,Concurrency,Atomic,原子XXX.lazySet(value)方法在大多数JMM推理中使用的“发生在边之前”是什么意思?javadocs在它上面是纯的,Sun bug声明: 语义是保证写入不会与任何以前的写入一起重新排序,但可以与后续操作一起重新排序(或者等效地,可能对其他线程不可见),直到发生其他易失性写入或同步操作为止 但这并不是关于HB边缘的推理,所以我很困惑。这是否意味着lazySet()语义不能用HB边来表达 更新:我将尝试具体化我的问题。我可以在以下场景中使用普通易失性字段: //thread 1: pr

原子XXX.lazySet(value)方法在大多数JMM推理中使用的“发生在边之前”是什么意思?javadocs在它上面是纯的,Sun bug声明:

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

但这并不是关于HB边缘的推理,所以我很困惑。这是否意味着lazySet()语义不能用HB边来表达

更新:我将尝试具体化我的问题。我可以在以下场景中使用普通易失性字段:

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

//thread 2: consumer
while(myVolatileFlag!=1){
   //spin-wait
}
...use data structure...
在这种情况下,在消费者中使用“数据结构”是正确的,因为易失性标志写-读使HB边缘,从而保证生产者对“数据结构”的所有写入都将完成,消费者可以看到。但是,如果在这个场景中使用AtomicInteger.lazySet/get而不是volatile write/read,该怎么办

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

//thread 2: consumer
while(myAtomicFlag.get()!=1){
   //spin-wait
}
...use data structure...
它仍然正确吗?我还真的可以在消费者线程中查看“数据结构”值吗


这不是“来自空中”的问题——我在LMAX中断器代码中看到过这种方法,但我不知道如何证明它是正确的…

基于不安全的Javadoc(putOrderedInt用于AtomicInteger.lazySet)

AtomicXXX类中的支持字段是可变的。懒散的人似乎在写这些字段时就好像它们不是易失性的,这将删除您期望的边。正如在您的链接中所指出的,这将有助于使值为空以符合GC的条件,而不必引起易失性写入

编辑:

这是为了回答您的更新

如果您查看从链接提供的引用,那么您就失去了对volatile write的任何内存保证


lazySet不会在写入位置的上方进行订购,但如果没有任何其他实际同步,您将无法保证使用者会看到之前写入的任何更改。延迟myAtomicFlag的写入是完全合法的,在其他形式的同步发生之前,在myAtomicFlag之前的任何写入都是合法的。

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

清空链表指针的垃圾收集示例没有用户可见的副作用。空值是首选的,这样如果列表中的节点处于不同的代中,就不会强制执行更昂贵的集合来丢弃链接链。lazySet的使用保持了卫生语义,而不会产生易失性写开销

另一个例子是使用由锁保护的易失性字段,例如在
ConcurrentHashMap
中。这些字段是可变的,允许无锁读取,但写入必须在锁下执行,以确保严格的一致性。由于锁保证了在发布边缘之前进行更新,因此一种优化方法是在写入字段时使用lazySet,在解锁时刷新所有更新。这有助于避免不必要的停车和公共汽车交通,从而缩短关键路段


如果编写并发数据结构,那么要注意
lazySet
。这是一个低级优化,因此只有在性能调整时才值得考虑。

感谢您的澄清。您还可以查看更新并对其进行评论吗?作为一个集合,而不是cas,只有当重要数据显示时不会覆盖时,它才是安全的。多个生产商将竞争一个时段,因此这并不安全。如果单个消费者耗尽了缓冲区,延迟了空闲插槽的可见性,这将是安全的。几个月前我在玩这个游戏,看我的代码。这是一个单一生产者/单一消费者案例。但我仍然不明白为什么它是安全的——我如何证明1)在sequence之前所做的写入。lazySet(seq)在sequence之后都完成了,并且对线程2可见。get()==seq?而懒散集(seq)实际上是在某个有限的时间里写成的:文档上写的是“最终”——这可能意味着“在一秒钟内”、“在一小时内”,甚至“永远不会”。如果将懒散集视为非易失性写入,编译器或处理器似乎可以自由地永远延迟它……你是对的——最终是不确定的。当缓存由于其他活动而刷新时,它是可见的。GC示例是乐观的,不依赖可见性来判断正确性。我的环形缓冲区示例使用锁释放实现可见性。在您的单一生产者/消费者示例中,我希望生产者稍后在已知点进行易变写入,以确保可见性。实际上,它很容易出错,但由于其他活动强制刷新,它可能会正常工作。如果您不能对代码的正确性进行推理,那么最好假设它是不正确的,即使它似乎可以工作。懒散集可以确保不进行写重新排序,但对于读一次,则不能这样做,即,在传播值之前可能会执行连续读取。对于x86,lazySet只是一条mov指令。在上面的例子中,懒散是好的,我。。。这是一个巨大的胜利。如果lazySet方法充当存储屏障,那么使用它是可以的。一旦thread2看到该标志,就可以读取该结构。lazySet确保写入在某一点上是可见的,并且所有架构都允许自动可见性,即,如果写入了某个内容,它将是可见的,并且最终是一致的。
/** 
 * Version of {@link #putObjectVolatile(Object, long, Object)}
 * that does not guarantee immediate visibility of the store to
 * other threads. This method is generally only useful if the
 * underlying field is a Java volatile (or if an array cell, one
 * that is otherwise only accessed using volatile accesses).
 */
public native void  putOrderedObject(Object o, long offset, Object x);

/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)}  */
public native void  putOrderedInt(Object o, long offset, int x);