AtomicInteger lazySet vs. set

JavaConcurrencyAtomic

Java Problem Overview


What is the difference between the lazySet and set methods of AtomicInteger? The documentation doesn't have much to say about lazySet:

> Eventually sets to the given value.

It seems that the stored value will not be immediately set to the desired value but will instead be scheduled to be set some time in the future. But, what is the practical use of this method? Any example?

Java Solutions


Solution 1 - Java

Cited straight from "JDK-6275329: Add lazySet methods to atomic classes":

> As probably the last little JSR166 follow-up for Mustang, we added a "lazySet" method to the Atomic classes (AtomicInteger, AtomicReference, etc). This is a niche method that is sometimes useful when fine-tuning code using non-blocking data structures. The semantics are that the write is guaranteed not to be re-ordered with any previous write, but may be reordered with subsequent operations (or equivalently, might not be visible to other threads) until some other volatile write or synchronizing action occurs).

> The main use case is for nulling out fields of nodes in non-blocking data structures solely for the sake of avoiding long-term garbage retention; it applies when it is harmless if other threads see non-null values for a while, but you'd like to ensure that structures are eventually GCable. In such cases, you can get better performance by avoiding the costs of the null volatile-write. There are a few other use cases along these lines for non-reference-based atomics as well, so the method is supported across all of the AtomicX classes.

> For people who like to think of these operations in terms of machine-level barriers on common multiprocessors, lazySet provides a preceeding store-store barrier (which is either a no-op or very cheap on current platforms), but no store-load barrier (which is usually the expensive part of a volatile-write).

Solution 2 - Java

lazySet can be used for rmw inter thread communication, because xchg is atomic, as for visibility, when writer thread process modify a cache line location, reader thread's processor will see it at the next read, because the cache coherence protocol of intel cpu will garantee LazySet works, but the cache line will be updated at the next read, again, the CPU has to be modern enough.

http://sc.tamu.edu/systems/eos/nehalem.pdf For Nehalem which is a multi-processor platform, the processors have the ability to “snoop” (eavesdrop) the address bus for other processor’s accesses to system memory and to their internal caches. They use this snooping ability to keep their internal caches consistent both with system memory and with the caches in other interconnected processors. If through snooping one processor detects that another processor intends to write to a memory location that it currently has cached in Shared state, the snooping processor will invalidate its cache block forcing it to perform a cache line fill the next time it accesses the same memory location.

oracle hotspot jdk for x86 cpu architecture->

lazySet == unsafe.putOrderedLong == xchg rw( asm instruction that serve as a soft barrier costing 20 cycles on nehelem intel cpu)

on x86 (x86_64) such a barrier is much cheaper performance-wise than volatile or AtomicLong getAndAdd ,

In an one producer, one consumer queue scenario, xchg soft barrier can force the line of codes before the lazySet(sequence+1) for producer thread to happen BEFORE any consumer thread code that will consume (work on) the new data, of course consumer thread will need to check atomically that producer sequence was incremented by exactly one using a compareAndSet (sequence, sequence + 1).

I traced after Hotspot source code to find the exact mapping of the lazySet to cpp code: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe.cpp Unsafe_setOrderedLong -> SET_FIELD_VOLATILE definition -> OrderAccess:release_store_fence. For x86_64, OrderAccess:release_store_fence is defined as using the xchg instruction.

You can see how it is exactly defined in jdk7 (doug lea is working on some new stuff for JDK 8): http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp

you can also use the hdis to disassemble the lazySet code's assembly in action.

There is another related question: https://stackoverflow.com/questions/9027590/do-we-need-mfence-when-using-xchg

Solution 3 - Java

A wider discussion of the origins and utility of lazySet and the underlying putOrdered can be found here: http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

To summarize: lazySet is a weak volatile write in the sense that it acts as a store-store and not a store-load fence. This boils down to lazySet being JIT compiled to a MOV instruction that cannot be re-ordered by the compiler rather then the significantly more expensive instruction used for a volatile set.

When reading the value you always end up doing a volatile read(with an Atomic*.get() in any case).

lazySet offers a single writer a consistent volatile write mechanism, i.e. it is perfectly legitimate for a single writer to use lazySet to increment a counter, multiple threads incrementing the same counter will have to resolve the competing writes using CAS, which is exactly what happens under the covers of Atomic* for incAndGet.

Solution 4 - Java

From the Concurrent-atomic package summary

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.

If you are curious about lazySet then you owe yourself other explanations too

> The memory effects for accesses and updates of atomics generally > follow the rules for volatiles, as stated in section 17.4 of The Java™ > Language Specification. > > get has the memory effects of reading a volatile variable. > > set has the memory effects of writing (assigning) a volatile variable. > > 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. > > weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides > no guarantees with respect to previous or subsequent reads and writes > of any variables other than the target of the weakCompareAndSet. > > compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing > volatile variables. > >

Solution 5 - Java

Here is my understanding, correct me if I am wrong: You can think about lazySet() as "semi" volatile: it's basically a non-volatile variable in terms of reading by other threads, i.e. the value set by lazySet may not be visible to to other threads. But it becomes volatile when another write operation occurs (may be from other threads). The only impact of lazySet I can imagine is compareAndSet. So if you use lazySet(), get() from other threads may still get the old value, but compareAndSet() will always have the new value since it is a write operation.

Solution 6 - Java

Re: attempt to dumb it down -

You can think of this as a way to treat a volatile field as if it wasn't volatile for a particular store (eg: ref = null;) operation.

That isn't perfectly accurate, but it should be enough that you could make a decision between "OK, I really don't care" and "Hmm, let me think about that for a bit".

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCheok Yan ChengView Question on Stackoverflow
Solution 1 - JavayawnView Answer on Stackoverflow
Solution 2 - JavaporkchopView Answer on Stackoverflow
Solution 3 - JavaNitsan WakartView Answer on Stackoverflow
Solution 4 - JavaAjeet GangaView Answer on Stackoverflow
Solution 5 - JavajyluoView Answer on Stackoverflow
Solution 6 - JavaPaul MclachlanView Answer on Stackoverflow