原子比较和交换是否可以覆盖惰性写入而不会看到它?

时间:2015-01-27 06:35:59

标签: java concurrency jls java-memory-model

JLS的memory model section (17.4)以合理的细节描述了volatile和非volatile读写的语义,以及与某些其他构造(如监视器进入和退出)的交互

但是,它并没有完全解释java.util.concurrent.Atomic *类中compareAndSwaplazySet的语义。对于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提供了一些更难以理解的模糊:

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?

锁存器不是问题的核心 - 它们只是让两个线程一直等到另一个完成的方式,并且在有趣的lazySetcompareAndSet操作之间强制执行在每个线程上,以及稍后读取原子以查看状态(没有它们,你当然可以看到至少val2 == 10,暂时)。

1 个答案:

答案 0 :(得分:2)

compareAndSet既是读取也是写入,因此它确实强加了写入排序约束。根据文档,这意味着lazySet写入将允许在其周围重新排序。所以不,val1val2永远不应该是10.

编辑:澄清一下,lazySet本质上做的是它为了也写到同一个东西的任何其他原子操作的目的而进行原子写入,但是非原子的对于仅读取的其他原子操作。

AtomicInteger lazySet vs. set更具潜在用途的讨论,最有用的信息是添加了延迟方法的原始变更集的链接:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329