JLS的memory model section (17.4)合理详细地描述了volatile
和非volatile
读写的语义,以及与某些其他构造(例如监视器进入和退出)的交互。
但是,它没有完全解释java.util.concurrent.Atomic *类上compareAndSwap
或lazySet
的语义。对于compareAndSet
,您确实具有package javadoc的内容:
compareAndSet and all other read-and-update operations such as getAndIncrement
have the memory effects of both reading and writing volatile variables.
lazySet
提供了更加难以理解的blurb:lazySet has the memory effects of writing (assigning) a volatile variable
except that it permits reorderings with subsequent (but not previous)
memory actions that do not themselves impose reordering constraints with
ordinary non-volatile writes. Among other usage contexts, lazySet may apply
when nulling out, for the sake of garbage collection, a reference that is
never accessed again.
我不清楚它们是如何相互作用的。如果您将CAS(
compareAndSet
)和lazySet发出到相同的原子值,而CAS ExpectedValue与lazySet值不同,那么CAS是否有可能覆盖lazySet值?更明确地讲,给定两个线程T1和T2,它们对共同的
AtomicInteger atomic = new AtomicInteger();
进行如下操作:static CountDownLatch latch = new CountDownLatch(2);
T1
atomic.lazySet(5); // L1A
latch.countDown();
latch.await();
int val1 = atomic.get();
T2
atomic.compareAndSet(0, 10); // L2A
latch.countDown();
latch.await();
int val2 = atomic.get();
val1 == val2 == 10
在这里可能吗?的确,val1
或val2
可以是10吗?锁存器不是问题的核心-它们只是让两个线程都等到另一个线程完成,然后强制在每个线程上有趣的
lazySet
和compareAndSet
操作之间进行操作,以及稍后读取原子的一种方式以查看状态(没有它们,您肯定可以至少暂时看到val2 == 10
)。 最佳答案
compareAndSet
既是读取又是写入,因此它确实施加了写入顺序约束。根据文档,这意味着lazySet
写入将被而不是围绕其重新排序。因此,不,val1
和val2
永远不应为10。
编辑:澄清一下,lazySet
本质上所做的是,它为任何也写入同一事物的其他原子操作目的而执行原子写入,但对于仅读取的其他原子操作则非原子操作。
在AtomicInteger lazySet vs. set上可能有更多有用的讨论,最有用的花絮是指向原始变更集的链接,其中添加了惰性方法:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329