[concurrency-interest] Atomic non-null then null

Dávid Karnok akarnokd at gmail.com
Wed Aug 8 17:36:46 EDT 2018


Hi Jeff,

Why the complication? Just return the value of `aRef` all the time. All
those extra code there with the additional read of `ref` and the
conditional checks look redundant as you'd probably have to null check the
result of your `get()` method anyway. Are you targeting a platform with an
expensive volatile read operation?

Jeff Hain via Concurrency-interest <concurrency-interest at cs.oswego.edu> ezt
írta (időpont: 2018. aug. 8., Sze, 23:23):

> Hello.
>
> Could someone confirm (or invalidate :) that the following class works?
>
> The "tricky part" is that get() is supposed to be callable concurrently.
> If it always gets called by a same thread, it should obviously work
> since only this thread would deal with the non-volatile reference.
>
>
>
> /**
>  * When wanting to retrieve an object from an AtomicReference
>  * that is initially non-null and then is only set once and with null,
>  * this class allows to get rid of the volatile read overhead
>  * after the nullification has been detected.
>  */
> public class AtomicNonNullThenNull<T> {
>
>     private final AtomicReference<T> aRef;
>
>     private Object ref = this;
>
>     /**
>      * @param aRef The initially non-null reference must be set into it
>      *        early enough for first call to get() method to see it.
>      */
>     public AtomicNonNullThenNull(AtomicReference<T> aRef) {
>         this.aRef = aRef;
>     }
>
>     /**
>      * Must only be called from threads to which the initial state
>      * of this instance has properly been made visible.
>      *
>      * @return The reference retrieved from the AtomicReference specified
>      *         to the constructor, until a call to this method detects that
>      *         it became null, after which null is always returned,
>      *         from a non-volatile read.
>      */
>     public T get() {
>         final Object ref = this.ref;
>         if (ref == null) {
>             return null;
>         } else {
>             final T vRef = this.aRef.get();
>             if (vRef == null) {
>                 // Possibly done by multiple threads.
>                 this.ref = null;
>                 return null;
>             } else {
>                 return vRef;
>             }
>         }
>     }
> }
>
>
>
> NB1: I use it in a method that gets called a lot,
> to do something once if it ever gets called,
> as follows:
>     final Runnable runnable = anntn.get();
>     if ((runnable != null) && aRef.compareAndSet(runnable, null)) {
>         runnable.run();
>     }
> I just read the discussion about "Unsynchronized lazy condition" from June,
> and the "Effective Java" class load trick, which seems to solve a similar
> problem.
> The cons that I see for the class load trick are that you need one class
> per use case,
> that it is always "slow" when it triggers (class load),
> and that it can only "fire" once (with ANNTN you could do aRef.set(null)
> only after a few runs),
> and the pro that in the long run the overhead is smaller due to the method
> being empty
> (unless the JIT can see that once the value is null it can never get back
> to non-null,
> and optimize the code away).
>
>
>
> NB2: There is a dual "AtomicNullThenNonNull" using a similar idea,
> but it only works with objects with final fields or such,
> since it can make them visible without proper memory barriers.
>
>
>
> -Jeff
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>


-- 
Best regards,
David Karnok
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20180808/2a1ed891/attachment.html>


More information about the Concurrency-interest mailing list