Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an Atomic compare and exchange overwrite a lazy write without seeing it?

The memory model section (17.4) of the JLS describes in reasonable detail the semantics of volatile and non-volatile reads and writes, as well as interaction with certain other constructs such as monitor enter and exit.

However, it doesn't completely explain the semantics of the compareAndSwap nor lazySet on the java.util.concurrent.Atomic* classes. For compareAndSet, you do have the blurb from the 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 offers the somewhat more inscrutable 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. 

What isn't clear to me is how they interact. If you issue a CAS (compareAndSet) and a lazySet to the same atomic value, where the CAS expectedValue is different than the lazySet value, is it possible that the CAS overwrites the lazySet value?

More explicitly, given two threads, T1 and T2, operating on a common AtomicInteger atomic = new AtomicInteger(); as follows:

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();

Is val1 == val2 == 10 a possible scenario here? Indeed, can val1 or val2 ever be 10?

The latches aren't core to the question - they are just a way of having both threads wait until the other is done, and forcing a happens before between the the interesting lazySet and compareAndSet operations on each thread, and the later reads of the atomic to see the state (without them, you could certainly see at least val2 == 10, transiently).

like image 954
BeeOnRope Avatar asked Jan 27 '15 06:01

BeeOnRope


1 Answers

compareAndSet is both a read and a write, therefore it does impose a write-ordering constraint. Per the docs, this means the lazySet write will not be allowed to be reordered around it. So no, val1 and val2 should never be 10.

EDIT: To clarify, what lazySet essentially does is that it acts an atomic write for the purposes of any other atomic operation that also writes to the same thing, but non-atomic for other atomic operations that are only reading.

More potentially useful discussion at AtomicInteger lazySet vs. set, the most useful tidbit being the link to the original changeset where the lazy methods were added: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329

like image 102
tzaman Avatar answered Oct 22 '22 14:10

tzaman