memory model section (17.4) JLS 的描述合理详细地描述了 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
提供了更难理解的内容:
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,它们在公共(public) 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
关于java - 原子比较和交换是否可以在看不到惰性写入的情况下覆盖它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28164581/