[concurrency-interest] The Atomic*FieldUpdater situation

David M. Lloyd david.lloyd at redhat.com
Sun Jul 15 12:19:17 EDT 2012


On 07/15/2012 06:14 AM, David Holmes wrote:
> David M. Lloyd writes:
>> What is the purpose of the access-time access check in the atomic field
>> updater classes?
>
> Do you mean the ensureProtectedAccess check?
>
> This is to ensure that you can't get an updater for a protected inherited
> field in SubtypeA, then use that updater to access/modify the field in an
> instance of SubtypeB.

Which is ridiculous because if a subclass "inherited" access to a normal 
protected field on my class, I'd still be able to access it directly in 
the base class... because fields aren't actually inherited.

>> If I construct an atomic field updater, to me, this should be exactly
>> equivalent to having an accessible=true Field instance.  If I want to
>> manage the visibility of that instance, I will restrict access to the
>> updater itself.
>>
>> The problem, as I am sure you are all well aware, is that when the
>> updater classes are used on an object instance which is subclassed, even
>> if the field being updated, the field updater, and the method calling
>> into the field updater all exist on the base class and are private, an
>> expensive access check has to occur.
>
> Now you've lost me. Which access check is this? All of the methods do:
>
> if (obj == null || obj.getClass() != tclass || cclass != null)
> fullCheck(obj);
>
> where fullCheck is:
>
>          private void fullCheck(T obj) {
>              if (!tclass.isInstance(obj))
>                  throw new ClassCastException();
>              if (cclass != null)
>                  ensureProtectedAccess(obj);
>          }
>
> and ensureProtectedAccess is:
>
>         private void ensureProtectedAccess(T obj) {
>              if (cclass.isInstance(obj)) {
>                  return;
>              }
>              throw new RuntimeException(
>                  new IllegalAccessException("Class " +
>                      cclass.getName() +
>                      " can not access a protected member of class " +
>                      tclass.getName() +
>                      " using an instance of " +
>                      obj.getClass().getName()
>                  )
>              );
>          }
>
> So if everything is in the same class we don't do any additional checks.

I believe this is inaccurate.  If I have a private static updater for a 
private field in the base class, and even if I access the updater only 
from the base class, the additional checks are still run because 
obj.getClass() != tclass (it's actually a subclass, not tclass).

But even if it weren't, the original access check is relatively 
expensive and completely unneeded.  Even assuming these access checks 
aren't completely pointless, which of course they are - if I want public 
access to a private field, I'd make the updater public.  If I want 
private access then the updater will be private.  No access-time checks 
are necessary; all the appropriate verification should have been done 
(usually at class init) when the updater is constructed by examining the 
caller class.  And I strongly, *strongly* doubt there is any code in the 
wild which relies on these access-time checks to ensure access protection.

And while I'm on this tirade - the whole design of using subclasses for 
the different variations in updater implementation seems unnecessary. 
If it were all in one final class, and the VM_SUPPORTS_LONG_CAS flag 
were a constant static field (which of course it is), then having e.g. 
compareAndSet be implemented like this:

public /*final*/ boolean compareAndSet(T obj, long expect, long update) {
     if (VM_SUPPORTS_LONG_CAS) {
         return unsafe.compareAndSwapLong(obj, offset, expect, update);
     } else synchronized (this) {
         long v = unsafe.getLong(obj, offset);
         if (v != expect) return false;
         unsafe.putLong(obj, offset, update);
         return true;
     }
}

...it seems to me that the method is much more likely to be inlined, and 
furthermore the un-followed branch should be elided, which would 
essentially make this a single instruction on most platforms.

>> Even when the class is final, the access check is still expensive
>> relative to the operation itself!
>>
>> I mean I'm using field updaters in the first place because I can't
>> afford to have a jillion Atomic* objects floating around; obviously
>> performance is critical here.  And to add to this problem, you can't
>> even rely on using Unsafe, even though it's becoming more and more
>> prevalent in JDKs, as some platforms may not have atomic 64-bit
>> operations, and there's no way I can see to test for that other than
>> relying on the AtomicLong implementation to be similar to OpenJDK's.
>>
>> Is there any recourse to solve this issue?
>> --
>> - DML
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>


-- 
- DML


More information about the Concurrency-interest mailing list