[concurrency-interest] Fwd: Should I avoid compareAndSet with value-based classes?

Gil Tene gil at azul.com
Fri Jul 7 13:02:47 EDT 2017


On Jul 7, 2017, at 6:52 AM, Andrew Haley <aph at redhat.com<mailto:aph at redhat.com>> wrote:

On 07/07/17 14:41, David Lloyd wrote:
On Fri, Jul 7, 2017 at 4:20 AM, Andrew Haley <aph at redhat.com<mailto:aph at redhat.com>> wrote:
In practice it doesn't matter, because you don't need to CAS a
reference to an Instant: all you need to do is to wrap all of the

I think you must have meant, "In practice it doesn't matter _in this
particular case_".  The problem of general data structures which use
CAS for updates matters very much in practice.

I'm talking about the problem of atomically updating an instance of a
value-based class while multiple threads are accessing it.  Unless I
am very much mistaken this thread is about no other subject.

You are right. That's the subject of the thread. And in some cases locking (on something other than the reference to the value-based class) will be perfectly sufficient. But in cases where people seek lock-free or wait-free operations, locking may not be an acceptable thing. E.g. Clocks and Instants are starting to show up in the low latency paths of FinServ software due to MiFID 2 requirements, and that sort of code often tries to avoid locking like the plague…

For reference, here are my variants of Michael's originally posted MutableClock (which is the thing that started this thread, I believe). They is still lock free, and CAS's on a boxed Instant to avoid the "compare" on undefined identity. MutableClock still supports sharing updates across clock instances, but UnsharedMutableClock is a [I think correct] variant where "shared updates" are not supported, and caches the Instant for faster read access.


public class MutableClock {

    public static MutableClock create(final Instant instant, final ZoneId zone) {
        return new MutableClock(
                new AtomicReference<>(new BoxedInstant(instant)),
                zone);
    }

    private final AtomicReference<BoxedInstant> instantHolder;
    private final ZoneId zone;

    private MutableClock(
            final AtomicReference<BoxedInstant> instantHolder,
            final ZoneId zone) {
        this.instantHolder = instantHolder;
        this.zone = zone;
    }

    public Instant instant() {
        return instantHolder.get().getInstant();
    }

    public ZoneId getZone() {
        return zone;
    }

    public void setInstant(final Instant newInstant) {
        instantHolder.get().setInstant(newInstant);
    }

    public void add(final Duration amountToAdd) {
        boolean success;
        do {
            BoxedInstant currentBoxedInstance = instantHolder.get();
            BoxedInstant newBoxedInstant =
                    new BoxedInstant(currentBoxedInstance.getInstant().plus(amountToAdd));
            success = instantHolder.compareAndSet(currentBoxedInstance, newBoxedInstant);
        } while (!success);
    }

    public MutableClock withZone(final ZoneId newZone) {
        // conveniently, AtomicReference also acts as a
        // vehicle for "shared updates" between instances:
        return new MutableClock(instantHolder, newZone);
    }

    private static class BoxedInstant {
        private Instant instant;

        BoxedInstant(final Instant instant) {
            setInstant(instant);
        }

        Instant getInstant() {
            return instant;
        }

        void setInstant(final Instant instant) {
            if (instant == null) {
                throw new UnsupportedOperationException("null instants are unsupported");
            }
            this.instant = instant;
        }
    }
}


public class UnsharedMutableClock {

    public static UnsharedMutableClock create(final Instant instant, final ZoneId zone) {
        return new UnsharedMutableClock(
                new AtomicReference<>(new BoxedInstant(instant)),
                zone);
    }

    private final AtomicReference<BoxedInstant> instantHolder;
    private final ZoneId zone;
    private Instant cachedInstant;
    private volatile boolean cacheIsValid = false;

    private UnsharedMutableClock(
            final AtomicReference<BoxedInstant> instantHolder,
            final ZoneId zone) {
        this.instantHolder = instantHolder;
        this.zone = zone;
        this.cachedInstant = instantHolder.get().getInstant();
    }

    public Instant instant() {
        if (!cacheIsValid) {
            cachedInstant = instantHolder.get().getInstant();
        }
        return cachedInstant;
    }

    public ZoneId getZone() {
        return zone;
    }

    public void setInstant(final Instant newInstant) {
        instantHolder.get().setInstant(newInstant);
        cacheIsValid = false;
    }

    public void add(final Duration amountToAdd) {
        boolean success;
        do {
            BoxedInstant currentBoxedInstance = instantHolder.get();
            BoxedInstant newBoxedInstant =
                    new BoxedInstant(currentBoxedInstance.getInstant().plus(amountToAdd));
            success = instantHolder.compareAndSet(currentBoxedInstance, newBoxedInstant);
        } while (!success);
        cacheIsValid = false;
    }

    private static class BoxedInstant {
        private Instant instant;

        BoxedInstant(final Instant instant) {
            setInstant(instant);
        }

        Instant getInstant() {
            return instant;
        }

        void setInstant(final Instant instant) {
            if (instant == null) {
                throw new UnsupportedOperationException("null instants are unsupported");
            }
            this.instant = instant;
        }
    }

}




--
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
_______________________________________________
Concurrency-interest mailing list
Concurrency-interest at cs.oswego.edu<mailto:Concurrency-interest at cs.oswego.edu>
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170707/edc5c12c/attachment-0001.html>


More information about the Concurrency-interest mailing list