[concurrency-interest] Java7 Fences API

Doug Lea dl at cs.oswego.edu
Tue Jan 13 10:05:20 EST 2009

[This is initially CCed to concurrency-interest list as an FYI,
but please direct followups to the JMM list only.]

The basic JSR133 JMM scheme provides three kinds of
underlying ordering constaints, that are tied to variable
declarations -- read-volatile, write-volatile, and
write-final (aka write-release, aka publish, aka lazy-set),
or for stand-alone AtomicX objects.

This turns out not to mesh very well with the development of
core concurrent algorithms (like the ones I tend to
implement), where you often need these special flavors of
reads and writes on an occasional basis, which is currently
either impossible or insensible to achieve.  As an example,
the performance sensitive queues underlying ForkJoin
require some critical write-releases of
variables/array-slots during ownership transfer.  These are
slightly more expensive than normal (non-volatile/final)
writes but much cheaper (in this context) than full

These also come into play in less esoteric usages. It is
very common to want to arrange a write-release to safely
publish a reference that could not be declared "final" for
one reason or another (for example because initialization
occurs in a callback).

Today, these usages cannot even be expressed without
cheating -- using the defacto-standard Unsafe API, which
truly is unsafe to use, so we really don't want people doing
this.  Things were not so bad when I and maybe 5 other
people were the only ones who cheated in this way, but more
and more people find that it is the only way to do it, so
do. Google reports estimated 8460 hits on "sun.misc.unsafe",
which probably corresponds to at least hundreds of
usages. Not good.  (Also, there are a couple of cases that
the current Unsafe API doesn't include, but should be in
place for Java7.)

In the recent C++0x standard, this kind of usage was
addressed by allowing per-usage modes on new read and write
methods. (And further, supporting more than the three modes
considered here, but I don't think we need to introduce more
for Java.)

We can't do this in Java, because Java does not support
call-by-reference. We cannot introduce an API with methods
that would be used like (using C addressof "&"):
   writeVolatile(&aField, aValue)

The closest you can come to this in Java is to include
similar methods in java.lang.reflect.{Field,Array}.  This is
an option, but not a very nice one. Even when optimized as
well as they can be on good JVMs, there is still enough
overhead to defeat the goals of using such methods.

Another tactic along these lines would be to lift
restrictions about volatileness inside
j.u.c.atomic.AtomicXFieldUpdaters, and similarly for array
versions. However, these encounter the same overhead
problem: They require internal dynamic type checks that are
(sometimes) tolerable for heavy operations like
compareAndSet (CAS) and writeVolatile, but surely not for
the above. (And stay tuned for some possible improvements in
these for CAS.)

So, after years of resisting the idea, my current conclusion
is that we need to stop wishing for a miraculous solution to
lack of call-by-ref, and instead allow developers to roll
their own out of the raw ingredients -- fences. There are
three kinds of fences that come into play here, best
illustrated by their usages in the above constructions for
some field/slot v, and local variable/expression r.  First
illustrated with argumentless fence methods:

readVolatile:  r = v; postLoadFence();
writeVolatile: preStoreFence(); v = r; postStorePreLoadFence();
writeFinal:    preStoreFence(); v = r;
   where {writeRelease, lazySet, publish} are same as writeFinal

JMM note: Recall that "final", and the above implementation
of writeFinal is "one-sided" -- in normal use it does not
require a readFinal counterpart. But if another thread has
already seen the ref (because of a leak before publishing)
then pretty much anything is allowed to happen. Here, it
would be allowed, but not required, to use readVolatile to
read it, which improves range of use a bit.

API note: The method names are intentionally clunky to avoid
the common mistake of putting read-fences before, not after,
reads, which sometimes intuitively looks correct but isn't,
and similarly for writes.  We've seen "experts" discussing
fences make this mistake, which suitable naming seems to fix.

The argument-ful versions of these methods allow tighter
specifications of effects, and closer correspondance to
typical read/write forms, by mentioning the object being
read/written.  These may enable a compiler to generate
better code by being less conservative about effects. Using
these versions to read a field of object x, you can do
   r = x.field; postLoadFence(x);
or even
   r = x.field; postLoadFence(x, xField);
where xField is the result of reflectively looking up
X.field.  These are optional in the Fences API because the
gain in precision is not always (or even usually) worth the
overhead of supplying this information.

All together, the Fences API seems to be the best of a bad
set of options. It provides the necessary capabilities, and,
as awkward/ugly as it is, it is vastly better than
continuing to implicitly invite developers to use Unsafe.

Also, their existence might drive better kinds of support
layered on top of them. Imperfect approaches to "nicer"
supprt include:

1. Macros. If there were a standard Java Macro preprocessor,
someone might introduce some (using C style for now):
    #define publish(v, r) preStoreFence(); v = r
Although even this could use C-like comma operator so it is
one expression. (And readVolatile is trickier still.)  As
overkill, maybe some AOP frameworks could be used in this

2. Syntax support via casts. Allow casted references well as
assignment. (You can't cast l-values because there are no

readVolatile:    r = ((volatile)x).field;
writeFinal:      x.field (final)= r;
writeVolatile:   x.field (volatile)= r;

The main weirdness is that "(final)=" doesn't mean what it
looks like, since it also serves as a writeRelease, which
need not be the only/last assignment. And in any case, it is
almost as ugly as using the Fence API, so I doubt that this
approach would be prioritized very highly when considering
syntactic Java language changes.

The specs of these methods still need some work -- I haven't
touched them since initially sketching them out last
year. Suggestions welcome.

At some point the JLS memory model specs would need to
reflect these changes.  Conceptually, it does not seem all
that hard to generalize the JMM to cover valriables that are
only sometimes (vs always) treated as volatile or final,
especially in comparison to other JMM spec problems that
someday need to be addressed (mainly, those described in
Jaroslav Sevcik's ECOOP08 paper).


More information about the Concurrency-interest mailing list