[concurrency-interest] jdk9 VarHandle and Fence methods

Doug Lea dl at cs.oswego.edu
Fri Aug 21 14:58:32 EDT 2015


For some similar questions and answers, see today's archives of
   jmm-dev:   http://mail.openjdk.java.net/mailman/listinfo/jmm-dev
   valhalla-dev: http://mail.openjdk.java.net/mailman/listinfo/valhalla-dev

On 08/21/2015 12:39 PM, Nathan Reynolds wrote:
> What is the difference between getRelaxed() and getOpaque()?  I realize that
> specifies the semantics of reading a non-volatile variable and the other has no
> guarantees what so ever.   What's up with reading a non-volatile variable?

getRelaxed is a plain ordinary read with rules specified by the JMM.
These APIs don't say what those rules are, allowing them to be revised.
But many reorderings and  transformations are allowed.

getOpaque is the same, but with the further constraint that the read
must actually occur even if other JMM rules would allow it to be
optimized away (for example due to common subexpression evaluation).
Usage is rare. Think IO.

>
> getOpaque() versus setVolatile() - Which one wins?

In the case I think you have in mind:  getX (X=relaxed, acquire, ...)
is a load. A preceding setVolatile entails what amount to a trailing
storeLoad fence, so cannot be reordered downward.

>
> For compareAndSet____() methods, should the variable names be (Object owner, T
> expect, T update) to match that of Atomic___ classes?

Probably so; thanks!

>
> Are you going to supply a web page similar to JSR 133 Cookbook?

Yes, that's the plan.

>
> I missed the conversation on reachabilityFence().  How do I use this?
>

You might glance through August 2014 jmm-dev mail with
"finalization" in subject.
   http://mail.openjdk.java.net/pipermail/jmm-dev/2014-August/thread.html

Also, here's a paste of draft javadocs from the last time we
considered this (5+ years ago):

Avoiding premature finalization. Finalization may occur whenever a Java Virtual 
Machine detects that no reference to an object will ever be stored in the heap: 
A garbage collector may reclaim an object even if the fields of that object are 
still in use, so long as the object has otherwise become unreachable. This may 
have surprising and undesirable effects in cases such as the following example 
in which the bookkeeping associated with a class is managed through array 
indices. Here, method action uses a reachabilityFence to ensure that the 
Resource object is not reclaimed before bookkeeping on an associated 
ExternalResource has been performed; in particular here, to ensure that the 
array slot holding the ExternalResource is not nulled out in method 
Object.finalize(), which may otherwise run concurrently.


  class Resource {
    private static ExternalResource[] externalResourceArray = ...

    int myIndex;
    Resource(...) {
      myIndex = ...
      externalResourceArray[myIndex] = ...;
      ...
    }
    protected void finalize() {
      externalResourceArray[myIndex] = null;
      ...
    }
    public void action() {
      try {
        // ...
        int i = myIndex;
        Resource.update(externalResourceArray[i]);
      } finally {
        Fences.reachabilityFence(this);
      }
    }
    private static void update(ExternalResource ext) {
      ext.status = ...;
    }
  }

Here, the call to reachabilityFence is nonintuitively placed after the call to 
update, to ensure that the array slot is not nulled out by Object.finalize() 
before the update, even if the call to action was the last use of this object. 
This might be the case if for example a usage in a user program had the form new 
Resource().action(); which retains no other reference to this Resource. While 
probably overkill here, reachabilityFence is placed in a finally block to ensure 
that it is invoked across all paths in the method. In a method with more complex 
control paths, you might need further precautions to ensure that 
reachabilityFence is encountered along all of them.

It is sometimes possible to better encapsulate use of reachabilityFence. 
Continuing the above example, if it were OK for the call to method update to 
proceed even if the finalizer had already executed (nulling out slot), then you 
could localize use of reachabilityFence:


  public void action2() {
    // ...
    Resource.update(getExternalResource());
  }
  private ExternalResource getExternalResource() {
    ExternalResource ext = externalResourceArray[myIndex];
    Fences.reachabilityFence(this);
    return ext;
  }

Method reachabilityFence is not required in constructions that themselves ensure 
reachability. For example, because objects that are locked cannot in general be 
reclaimed, it would suffice if all accesses of the object, in all methods of 
class Resource (including finalize) were enclosed in synchronized (this) blocks. 
(Further, such blocks must not include infinite loops, or themselves be 
unreachable, which fall into the corner case exceptions to the "in general" 
disclaimer.) However, method reachabilityFence remains a better option in cases 
where this approach is not as efficient, desirable, or possible; for example 
because it would encounter deadlock.




More information about the Concurrency-interest mailing list