You are correct that there is a problem here but not because of the 
unsafe.putIntVolatile. The problem is that hashSeed = 0; is a compile time 
constant and field accesses are elided in the compiled methods.

The idiom of setting a final field via unsafe.putIntVolatile is adapted from 
the deserialization code of ConcurrentHashMap. I've assumed that the memory 
model is correct. Objects being deserialized usually aren't visible to other 
threads (and the implementation of HashMap doesn't allow itself to be made 
visible to other threads during deserialization). I am less certain about the 
unsafe.putIntVolatile in initHashSeedAsNeeded and may just make hashSeed 
non-final.

I will correct the patch so that hashSeed isn't a compile time constant.

:-(

Mike

On Mar 4 2013, at 14:14 , Peter Levart wrote:

> Hi mike,
> 
> I doubt (haven't tried it really with your code) that hashSeed will be seen 
> by code to be anything else but 0, since it is initialized to a constant 
> value. For example, this code:
> 
> public class ModifyingFinalTest {
>     static final Unsafe unsafe;
>     static final long valueOffset;
> 
>     static {
>         try {
>             Field f = Unsafe.class.getDeclaredField("theUnsafe");
>             f.setAccessible(true);
>             unsafe = (Unsafe)f.get(null);
>             valueOffset = 
> unsafe.objectFieldOffset(ModifyingFinalTest.class.getDeclaredField("value"));
>         }
>         catch (IllegalAccessException | NoSuchFieldException e) {
>             throw new Error(e);
>         }
>     }
> 
>     final int value = 0;
> 
>     void test() {
>         unsafe.putIntVolatile(this, valueOffset, 1);
>         printValue();
>         unsafe.putIntVolatile(this, valueOffset, 2);
>         printValue();
>         unsafe.putIntVolatile(this, valueOffset, 3);
>         printValue();
>     }
> 
>     void printValue() {
>         System.out.println(value);
>     }
> 
>     public static void main(String[] args) {
>         new ModifyingFinalTest().test();
>     }
> }
> 
> 
> Prints:
> 
> 0
> 0
> 0
> 
> 
> It's a different thing, if the initialization is changed to:
> 
> final int value = "".length();
> 
> But I don't know if each access in source is actually guaranteed to translate 
> to a real read of field in this case either. Is Unsafe.putIntVolatile() 
> making this happen somehow magically?
> 
> Regards, Peter
> 
> 
> On 03/04/2013 09:21 PM, Mike Duigou wrote:
>> Hello all;
>> 
>> The alternative hashing implementation introduced in 7u6 added an 
>> unfortunate bottleneck to the initialization of HashMap and Hashtable 
>> instances. This patch avoids the performance bottleneck of using a shared 
>> Random instance by using a ThreadLocalRandom instead.
>> 
>> Along with this change are some additional performance improvements to 
>> further reduce the overhead of the alternative hashing feature and generally 
>> improve the performance of Hashtable or HashMap.
>> 
>> http://cr.openjdk.java.net/~mduigou/JDK-8006593/3/webrev/
>> 
>> Once review is completed here this patch will be proposed to JDK7u-dev for 
>> integration into the next 7u performance/feature release.
>> 
>> Mike
>> 
> 

Reply via email to