[concurrency-interest] jdk9 VarHandle and Fence methods

Doug Lea dl at cs.oswego.edu
Fri Aug 21 09:44:15 EDT 2015


For those of you who haven't been following this on the jmm-dev list:

We are NOT planning a full JMM memory model update for jdk9 -- there
are still unresolved issues in revising the formal core model.
However, jdk9 will include APIs for VarHandles (a scaled-down version of
the "enhanced volatiles" JEP), that together with some other
support replaces the need to use of Unsafe to obtain these
effects and does so compatibly with C/C++11 atomics. To do this, we
must, until the next full JMM update, provide specs that are
clear to readers (at least those familiar with the underlying
concepts) but not formally tied to a base model, (Which limits
how much we can say in them.)

The tentative methods are pasted below and also at
   http://gee.cs.oswego.edu/dl/wwwtmp/Fodder.java
The javadocs currently do not include any examples helping to
explain why you would ever want to use any of these methods.

The actual VarHandle class will look a bit different because
it will rely on specializations of polymorphic signatures.
(Current versions can be found in the openjdk mercurial
"jdk9/sandbox" repo.) And the "Fences" method may end up
in a different java.lang.* utility class. We'd also retrofit
j.u.c.atomic.Atomic* classes to use compatible methods/names.

Comments welcome.

...

/**
  * Stand-in for spec purposes of jdk9 java.lang.invoke.VarHandle
  */
abstract class NotReallyVarHandle<T> {
     // Load

     /**
      * Returns the value, with memory semantics of reading a
      * non-volatile variable.
      *
      * @return the value
      */
     T getRelaxed(Object owner);

     /**
      * Returns the value, with memory semantics of reading a volatile
      * variable.
      *
      * @return the value
      */
     T getVolatile(Object owner);

     /**
      * Returns the value, and ensures that subsequent loads and stores
      * are not reordered before this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_acquire ordering.
      *
      * @return the value
      */
     T getAcquire(Object owner);

     /**
      * Returns the value, accessed in program order, but with no
      * assurance of memory ordering effects with respect to other
      * threads.
      *
      * @return the value
      */
     T getOpaque(Object owner);

     // Store

     /**
      * Sets the value, with memory semantics of setting a non-volatile
      * variable.
      *
      * @param val the new value
      */
     void setRelaxed(Object owner, T val);

     /**
      * Sets the value, with memory semantics of setting a volatile
      * variable.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_seq_cst.
      *
      * @param val the new value
      */
     void setVolatile(Object owner, T val);

     /**
      * Sets the value, and ensures that prior loads and stores are not
      * reordered after this access.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * memory_order_release ordering.
      *
      * @param val the new value
      */
     void setRelease(Object owner, T val);

     /**
      * Sets the value, in program order, but with no assurance of
      * memory ordering effects with respect to other threads.
      *
      * @param val the new value
      */
     void setOpaque(Object owner, T val);

     // CAS

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setVolatile if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getVolatile.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful. False return indicates that
      * the actual value was not equal to the expected value.
      */
     boolean compareAndSet(Object owner, T expected, T val);

     // Value-returning compare and exchange

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setVolatile if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getVolatile.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeVolatile(Object owner, T expected, T val);

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setRelaxed if the current value {@code ==}
      * the expected value, as accessed with the memory semantics of
      * getAcquire.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeAcquire(Object owner, T expected, T val);

     /**
      * Atomically sets the value to the given updated value with the
      * memory semantics of setRelease if the current value {@code ==}
      * the expected value, as accessed with the memory samantics of
      * getRelease.
      *
      * @param expected the expected value
      * @param val the new value
      * @return the current value, which will be the same as {@code val} if
      * successful.
      */
     T compareAndExchangeRelease(Object owner, T expected, T val);

     // Weak (spurious failures allowed)

     /**
      * Possibly atomically sets the value to the given updated value
      * with the semantics of setRelaxed if the current value {@code
      * ==} the expected value, as as accessed with the memory
      * semantics of getRelaxed.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetRelaxed(Object owner, T expected, T val);

     /**
      * Possibly atomically sets the value to the given updated value
      * with the memory semantics of setRelaxed if the current value
      * {@code ==} the expected value, as as accessed with the memory
      * semantics of getAcquire.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetAcquire(Object owner, T expected, T val);

     /**
      * Possibly atomically sets the value to the given updated value
      * with the memory semantics of setRelease if the current value
      * {@code ==} the expected value, as as accessed with the memory
      * semantics of getRelaxed.  This operation may fail spuriously
      * (typically, due to memory contention) even if the current value
      * does match the expected value.
      *
      * @param expected the expected value
      * @param val the new value
      * @return {@code true} if successful
      */
     boolean weakCompareAndSetRelease(Object owner, T expected, T val);

     // special RMW

     /**
      * Atomically sets to the given value with the memory semantics of
      * setVolatile and returns the old value.
      *
      * @param newValue the new value
      * @return the previous value
      */
     T getAndSet(Object owner, T val);

     /**
      * Atomically adds the given value to the current value with the
      * memory semantics of setVolatile.
      *
      * @param delta the value to add
      * @return the previous value
      */
     T getAndAdd(Object owner, T delta);

     /**
      * Atomically adds the given value to the current value with the
      * memory semantics of setVolatile.
      *
      * @param delta the value to add
      * @return the current value
      */
     T addAndGet(Object owner, T delta);
}

/**
  * A set of methods providing fine-grained control of memory ordering.
  *
  * <p>The Java Language Specification permits operations to be
  * executed in orders different than are apparent in program source
  * code, subject to constraints mainly arising from the use of locks
  * and volatile fields. The methods of this class can also be used to
  * impose constraints. Their specifications are phrased in terms of
  * the lack of "reorderings" -- observable ordering effects that might
  * otherwise occur if the fence were not present.
  *
  * @apiNote More precise phrasing of these specifications may
  * accompany future updates of the Java Language Specification.
  */
public class Fences {

     /**
      * Ensures that loads and stores before the fence will not be
      * reordered with loads and stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_seq_cst)
      */
     public static void fullFence() {}

     /**
      * Ensures that loads before the fence will not be reordered with
      * loads and stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_acquire)
      */
     public static void acquireFence() {}

     /**
      * Ensures that loads and stores before the fence will not be
      * reordered with stores after the fence.
      *
      * @apiNote Ignoring the many semantic differences from C and
      * C++, this method has memory ordering effects compatible with
      * atomic_thread_fence(memory_order_release)
      */
     public static void releaseFence() {}

     /**
      * Ensures that loads before the fence will not be reordered with
      * loads after the fence.
      */
     public static void loadLoadFence() {}

     /**
      * Ensures that stores before the fence will not be reordered with
      * stores after the fence.
      */
     public static void storeStoreFence() {}

}

class java.lang.ref.Reference {
     // add:

     /**
      * Ensures that the object referenced by the given reference
      * remains <em>strongly reachable</em> (as defined in the {@link
      * java.lang.ref} package documentation), regardless of any prior
      * actions of the program that might otherwise cause the object to
      * become unreachable; thus, the referenced object is not
      * reclaimable by garbage collection at least until after the
      * invocation of this method. Invocation of this method does not
      * itself initiate garbage collection or finalization.
      *
      * @param ref the reference. If null, this method has no effect.
      */
     public static void reachabilityFence(Object ref) {}

}


More information about the Concurrency-interest mailing list