From a9c908bcb35eab0a6068ec0f51624c2ef1e1471f Mon Sep 17 00:00:00 2001
From: Doug Lea
Date: Thu, 3 Mar 2016 10:39:34 -0800
Subject: [PATCH] 8150417: Make ThreadLocalRandom more robust against static
initialization cycles
Reviewed-by: martin, psandoz, dholmes, mhaupt
---
.../classes/java/util/SplittableRandom.java | 21 ++--
.../util/concurrent/ThreadLocalRandom.java | 113 +++++++++---------
2 files changed, 69 insertions(+), 65 deletions(-)
diff --git a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java
index f54b3d931b2..579102a2bc7 100644
--- a/jdk/src/java.base/share/classes/java/util/SplittableRandom.java
+++ b/jdk/src/java.base/share/classes/java/util/SplittableRandom.java
@@ -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 to survive static initialization circularity
+ static {
if (java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
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
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
index 3e50171cf20..69ecc46cf6d 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java
@@ -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() {
- 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 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 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 to survive static initialization circularity
+ static {
+ if (java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ 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);
+ }
+ }
}