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();