8150417: Make ThreadLocalRandom more robust against static initialization cycles

Reviewed-by: martin, psandoz, dholmes, mhaupt
This commit is contained in:
Doug Lea 2016-03-03 10:39:34 -08:00
parent 90771aabae
commit a9c908bcb3
2 changed files with 69 additions and 65 deletions

View File

@ -219,12 +219,20 @@ public final class SplittableRandom {
return seed += gamma;
}
// IllegalArgumentException messages
static final String BAD_BOUND = "bound must be positive";
static final String BAD_RANGE = "bound must be greater than origin";
static final String BAD_SIZE = "size must be non-negative";
/**
* The seed generator for default constructors.
*/
private static final AtomicLong defaultGen = new AtomicLong(initialSeed());
private static final AtomicLong defaultGen
= new AtomicLong(mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
private static long initialSeed() {
// at end of <clinit> to survive static initialization circularity
static {
if (java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Boolean>() {
public Boolean run() {
@ -234,17 +242,10 @@ public final class SplittableRandom {
long s = (long)seedBytes[0] & 0xffL;
for (int i = 1; i < 8; ++i)
s = (s << 8) | ((long)seedBytes[i] & 0xffL);
return s;
defaultGen.set(s);
}
return (mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
}
// IllegalArgumentException messages
static final String BAD_BOUND = "bound must be positive";
static final String BAD_RANGE = "bound must be greater than origin";
static final String BAD_SIZE = "size must be non-negative";
/*
* Internal versions of nextX methods used by streams, as well as
* the public nextX(origin, bound) methods. These exist mainly to

View File

@ -125,53 +125,6 @@ public class ThreadLocalRandom extends Random {
* but we provide identical statistical properties.
*/
/** Generates per-thread initialization/probe field */
private static final AtomicInteger probeGenerator = new AtomicInteger();
/**
* The next seed for default constructors.
*/
private static final AtomicLong seeder = new AtomicLong(initialSeed());
private static long initialSeed() {
if (java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.getBoolean("java.util.secureRandomSeed");
}})) {
byte[] seedBytes = java.security.SecureRandom.getSeed(8);
long s = (long)seedBytes[0] & 0xffL;
for (int i = 1; i < 8; ++i)
s = (s << 8) | ((long)seedBytes[i] & 0xffL);
return s;
}
return (mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
}
/**
* The seed increment.
*/
private static final long GAMMA = 0x9e3779b97f4a7c15L;
/**
* The increment for generating probe values.
*/
private static final int PROBE_INCREMENT = 0x9e3779b9;
/**
* The increment of seeder per new instance.
*/
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
// Constants from SplittableRandom
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)
/** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal<Double> nextLocalGaussian =
new ThreadLocal<>();
private static long mix64(long z) {
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
@ -194,9 +147,6 @@ public class ThreadLocalRandom extends Random {
initialized = true; // false during super() call
}
/** The common ThreadLocalRandom */
static final ThreadLocalRandom instance = new ThreadLocalRandom();
/**
* Initialize Thread fields for the current thread. Called only
* when Thread.threadLocalRandomProbe is zero, indicating that a
@ -248,11 +198,6 @@ public class ThreadLocalRandom extends Random {
return (int)(mix64(nextSeed()) >>> (64 - bits));
}
// IllegalArgumentException messages
static final String BAD_BOUND = "bound must be positive";
static final String BAD_RANGE = "bound must be greater than origin";
static final String BAD_SIZE = "size must be non-negative";
/**
* The form of nextLong used by LongStream Spliterators. If
* origin is greater than bound, acts as unbounded form of
@ -1050,6 +995,32 @@ public class ThreadLocalRandom extends Random {
return current();
}
// Static initialization
/**
* The seed increment.
*/
private static final long GAMMA = 0x9e3779b97f4a7c15L;
/**
* The increment for generating probe values.
*/
private static final int PROBE_INCREMENT = 0x9e3779b9;
/**
* The increment of seeder per new instance.
*/
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
// Constants from SplittableRandom
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)
// IllegalArgumentException messages
static final String BAD_BOUND = "bound must be positive";
static final String BAD_RANGE = "bound must be greater than origin";
static final String BAD_SIZE = "size must be non-negative";
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long SEED;
@ -1067,4 +1038,36 @@ public class ThreadLocalRandom extends Random {
throw new Error(e);
}
}
/** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal<Double> nextLocalGaussian =
new ThreadLocal<>();
/** Generates per-thread initialization/probe field */
private static final AtomicInteger probeGenerator = new AtomicInteger();
/** The common ThreadLocalRandom */
static final ThreadLocalRandom instance = new ThreadLocalRandom();
/**
* The next seed for default constructors.
*/
private static final AtomicLong seeder
= new AtomicLong(mix64(System.currentTimeMillis()) ^
mix64(System.nanoTime()));
// at end of <clinit> to survive static initialization circularity
static {
if (java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.getBoolean("java.util.secureRandomSeed");
}})) {
byte[] seedBytes = java.security.SecureRandom.getSeed(8);
long s = (long)seedBytes[0] & 0xffL;
for (int i = 1; i < 8; ++i)
s = (s << 8) | ((long)seedBytes[i] & 0xffL);
seeder.set(s);
}
}
}