src/share/classes/java/util/Hashtable.java

Print this page

        

*** 166,216 **** /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1421746759512286392L; private static class Holder { ! // Unsafe mechanics ! /** ! * ! */ ! static final sun.misc.Unsafe UNSAFE; ! ! /** ! * Offset of "final" hashSeed field we must set in ! * readObject() method. ! */ ! static final long HASHSEED_OFFSET; static { ! try { ! UNSAFE = sun.misc.Unsafe.getUnsafe(); ! HASHSEED_OFFSET = UNSAFE.objectFieldOffset( ! Hashtable.class.getDeclaredField("hashSeed")); ! } catch (NoSuchFieldException | SecurityException e) { ! throw new InternalError("Failed to record hashSeed offset", e); ! } } } /** * A randomizing value associated with this instance that is applied to * hash code of keys to make hash collisions harder to find. */ ! transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this); ! private int hash(Object k) { ! if (k instanceof String) { ! return ((String)k).hash32(); } ! int h = hashSeed ^ k.hashCode(); ! ! // This function ensures that hashCodes that differ only by ! // constant multiples at each bit position have a bounded ! // number of collisions (approximately 8 at default load factor). ! h ^= (h >>> 20) ^ (h >>> 12); ! return h ^ (h >>> 7) ^ (h >>> 4); } /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor. --- 166,208 ---- /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1421746759512286392L; private static class Holder { ! static final boolean USE_HASHSEED; static { ! String hashSeedProp = java.security.AccessController.doPrivileged( ! new sun.security.action.GetPropertyAction( ! "jdk.map.useRandomSeed")); ! boolean localBool = (null != hashSeedProp) ! ? Boolean.parseBoolean(hashSeedProp) : false; ! USE_HASHSEED = localBool; } } /** * A randomizing value associated with this instance that is applied to * hash code of keys to make hash collisions harder to find. + * + * Non-final so it can be set lazily, but be sure not to set more than once. */ ! transient int hashSeed; ! /** ! * Initialize the hashing mask value. ! */ ! final void initHashSeed() { ! if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { ! // Do not set hashSeed more than once! ! // assert hashSeed == 0; ! hashSeed = sun.misc.Hashing.randomHashSeed(this); ! } } ! private int hash(Object k) { ! return hashSeed ^ k.hashCode(); } /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor.
*** 230,239 **** --- 222,232 ---- if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); + initHashSeed(); } /** * Constructs a new, empty hashtable with the specified initial capacity * and default load factor (0.75).
*** 1184,1197 **** throws IOException, ClassNotFoundException { // Read in the length, threshold, and loadfactor s.defaultReadObject(); - // set hashMask - Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, - sun.misc.Hashing.randomHashSeed(this)); - // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt(); // Compute new size with a bit of room 5% to grow but --- 1177,1186 ----
*** 1204,1213 **** --- 1193,1203 ---- if (origlength > 0 && length > origlength) length = origlength; table = new Entry<?,?>[length]; threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); count = 0; + initHashSeed(); // Read the number of elements and then all the key/value objects for (; elements > 0; elements--) { @SuppressWarnings("unchecked") K key = (K)s.readObject();