[concurrency-interest] Fences, AtomicXFieldUpdater enhancements, and @Racy annotations

Peter Veentjer alarmnummer at gmail.com
Fri Jan 16 10:00:21 EST 2009


Hi Doug,

can you tell us something about the internals of the atomic field
updaters? Do they work based on reflection, if yes, what is the
performance impact?

And what is the performance compared to a normal AtomicXXX class?

On Fri, Jan 16, 2009 at 2:43 PM, Doug Lea <dl at cs.oswego.edu> wrote:
> [This one is equally on java.util.concurrent and JMM issues,
> so please be tolerant of cross-post duplication.]
>
> First, I'm getting more confident that the specs for Fence
> API are in the right ballpark, although still need a bit
> more precision in the discussion of "scopes".  (If anyone
> want to help, please do!) See the updated draft
> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java/util/concurrent/atomic/Fences.html
>
> Second, I am continuing my crusade to rid the world of
> explicit use of "sun.misc.Unsafe". And these plans might
> mesh well with the usage concerns that Bill Pugh and I have
> discussed and that he's posted about (as in: "yow" :-)
>
> Here's the story.
>
> As mentioned in my initial posting on Fences (1) everyone would
> be happier if they almost never had to use them directly, but
> instead could get the effects via methods with recognizable
> semantics (2) people can get some of these effects already by
> using AtomicXFieldUpdaters, but even in those cases often don't.
>
> We can address these, and make AtomicXFieldUpdaters
> (1) Applicable in more contexts
> (2) Cheaper in most cases where performance matters.
> (3) Better advertise intent
>
> Background. For those who have never used them,
> AtomicXFieldUpdaters are ugly to declare, but provide
> operations like compareAndSet to (volatile) fields of
> objects directly, without needing to create stand-alone
> AtomicX objects. (If you don't do a lot of low/medium-level
> parallel/concurrent programming, you might not think this is
> a big deal.  But it is: footprint, locality, and indirection
> hurt a lot more here than in sequential programs.)
>
> Here's a sample usage (pasted from ConcurrentSkipListMap)
>
> public class ConcurrentSkipListMap<K,V> ....  {
>    /**
>     * The topmost head index of the skiplist.
>     */
>    private transient volatile HeadIndex<K,V> head;
>
>    private static final
>        AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex>
>        headUpdater = AtomicReferenceFieldUpdater.newUpdater
>        (ConcurrentSkipListMap.class, HeadIndex.class, "head");
>
>    /**
>     * compareAndSet head node
>     */
>    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
>        return headUpdater.compareAndSet(this, cmp, val);
>    }
>
>    // ...
> }
>
> We can't do much about the 4 lines it takes to declare
> one of these (maybe IDEs could help), but we can address
> the other problems.
>
> 1. Less restrictive API
>
> Right now, we require that the target field be "volatile",
> and don't support any non-volatile, "relaxed" operations
> through it. As we've been discussing wrt Fences, there are
> use cases where these arise. We can support them by lifting
> volatile field declaration restriction and/or supplying two
> additional methods (illustrated with
> AtomicIntegerFieldUpdater).
>
>    /**
>     * Gets the value held in the field of the given object managed
>     * by this updater, using non-volatile memory consistency rules.
>     *
>     * @param obj An object whose field to get
>     * @return the current value
>     */
>    public abstract int relaxedGet(T obj);
>
>    /**
>     * Sets the field of the given object managed by this updater to the
>     * given updated value using non-volatile memory consistency rules.
>     *
>     * @param obj An object whose field to set
>     * @param newValue the new value
>     */
>    public abstract void relaxedSet(T obj, int newValue);
>
> (Additionally, we need to include AtomicXArrayUpdater
> classes, that differ from AtomicXArrays in that you hand an
> existing array to constructor/factory-method. We had been
> resisting this for similar reasons.)
>
>
> 2. Better typical performance
>
> First, more background:
>
> When people use Unsafe rather than updaters, it is often
> because they have discovered that there is non-trivial
> dynamic check overhead when using updater methods -- this
> overhead dwarfs that of some of the simpler operations like
> get(). The reason these checks exist is that even though all
> usages are statically typesafe with respect to a Java
> compiler, we must protect against people writing raw
> bytecode that uses the underlying intrinsics to access
> inaccessbile data etc. Such code can otherwise make it
> through class loading checks etc, so must be screened.
>
> The now common "try to use Unsafe anyway" hacks (like those
> near the bottom of the preliminary releases of jsr166y
> classes like ForkJoinPool), exist solely to bypass this: If
> the class/caller is allowed to use Unsafe because it is in
> bootclasspath or the program has no SecurityManager, or one
> that allows access to Unsafe, then do so, else abort.
>
> The improvement to updaters is to automate and extend this
> hack: If you are allowed to access Unsafe, provide an
> updater that bypasses checks, else the slower kind (rather
> than aborting). Luckily we use static factories here so this
> part is straightforward. This is a little tricky to set up
> but seems doable, subject to review of mechanics by security
> folks.
>
> The net result is that updaters will have performance that
> should be identical to raw Unsafe calls in usages that do
> not require security checks, which is very likely to include
> most performance-sensitive applications.  Those that do need
> checks will be slower, but for good reason.
>
> 3. Better advertised use
>
> The above changes will make updaters a lot more useful and
> probably a lot more used.  In fact, there are reasonable
> ways to use them to get almost all the effects of Fences
> (not quite all though).
>
> But with power comes responsibility.
> One downside of updaters is that the declaration of
> an updater is removed from the declaration of the field
> it is updating, which makes usage hard to check.
>
> This is where annotations can help: Any field that
> will be used via an updater should have some annotation
> saying so. One good candidate name for this annotation is
>  @Racy
> The reasoning is that any such variable is allowed
> to be used in ways that "don't count" with respect
> to the usual definitions of race-freedom.
>
> I don't think it is essential that @Racy be a required
> annotation that is checked by javac, but it is essential
> for extended checkers, which could help enforce the
> typically (but probably not universally) desirable
> requirement that if a variable is declared as
> @Racy, then ALL reads and writes of it must go through updaters.
>
> It's further possible to make @Racy take some sort of
> argument expressing intent, like @Racy("Publish").  But if
> this goes anywhere, these issues are probably best left to
> JSR305.
>
> Aside to Paul McKenney and other foreigners.  Notice that,
> under this scheme, @Racy is nearly synonymous with C++0x "atomic"
> but has a much more accurate name :-)
>
> -Doug
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>


More information about the Concurrency-interest mailing list