diff -r c646b256fbcc -r 6d87e9f7a1ec newrandom/ThreadLocalRandom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/newrandom/ThreadLocalRandom.java Thu May 23 16:45:56 2019 -0400 @@ -0,0 +1,386 @@ +/* + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +/* + * + * + * + * + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// package java.util.concurrent; + +import java.io.ObjectStreamField; +import java.math.BigInteger; +// import java.util.Random; +import java.util.Spliterator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + *

Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + *

This class also provides additional commonly used bounded random + * generation methods. + * + *

Instances of {@code ThreadLocalRandom} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} + * in security-sensitive applications. Additionally, + * default-constructed instances do not use a cryptographically random + * seed unless the {@linkplain System#getProperty system property} + * {@code java.util.secureRandomSeed} is set to {@code true}. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + /* + * This class implements the java.util.Random API (and subclasses + * Random) using a single static instance that accesses random + * number state held in class Thread (primarily, field + * threadLocalRandomSeed). In doing so, it also provides a home + * for managing package-private utilities that rely on exactly the + * same state as needed to maintain the ThreadLocalRandom + * instances. We leverage the need for an initialization flag + * field to also use it as a "probe" -- a self-adjusting thread + * hash used for contention avoidance, as well as a secondary + * simpler (xorShift) random seed that is conservatively used to + * avoid otherwise surprising users by hijacking the + * ThreadLocalRandom sequence. The dual use is a marriage of + * convenience, but is a simple and efficient way of reducing + * application-level overhead and footprint of most concurrent + * programs. + * + * Even though this class subclasses java.util.Random, it uses the + * same basic algorithm as java.util.SplittableRandom. (See its + * internal documentation for explanations, which are not repeated + * here.) Because ThreadLocalRandoms are not splittable + * though, we use only a single 64bit gamma. + * + * Because this class is in a different package than class Thread, + * field access methods use Unsafe to bypass access control rules. + * To conform to the requirements of the Random superclass + * constructor, the common static ThreadLocalRandom maintains an + * "initialized" field for the sake of rejecting user calls to + * setSeed while still allowing a call from constructor. Note + * that serialization is completely unnecessary because there is + * only a static singleton. But we generate a serial form + * containing "rnd" and "initialized" fields to ensure + * compatibility across versions. + * + * Implementations of non-core methods are mostly the same as in + * SplittableRandom, that were in part derived from a previous + * version of this class. + * + * The nextLocalGaussian ThreadLocal supports the very rarely used + * nextGaussian method by providing a holder for the second of a + * pair of them. As is true for the base class version of this + * method, this time/space tradeoff is probably never worthwhile, + * 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(RngSupport.initialSeed()); + + /** + * 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; + return z ^ (z >>> 33); + } + + private static int mix32(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; + return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32); + } + + /** + * Field used only during singleton initialization. + * True when constructor completes. + */ + boolean initialized; + + /** Constructor used only for static singleton */ + private ThreadLocalRandom() { + 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 + * thread local seed value needs to be generated. Note that even + * though the initialization is purely thread-local, we need to + * rely on (static) atomic generators to initialize the values. + */ + static final void localInit() { + int p = probeGenerator.addAndGet(PROBE_INCREMENT); + int probe = (p == 0) ? 1 : p; // skip 0 + long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT)); + Thread t = Thread.currentThread(); + UNSAFE.putLong(t, SEED, seed); + UNSAFE.putInt(t, PROBE, probe); + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0) + localInit(); + return instance; + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + // only allow call from super() constructor + if (initialized) + throw new UnsupportedOperationException(); + } + + final long nextSeed() { + Thread t; long r; // read and update per-thread seed + UNSAFE.putLong(t = Thread.currentThread(), SEED, + r = UNSAFE.getLong(t, SEED) + GAMMA); + return r; + } + + // We must define this (to override the definition inherited from + // class Random), but we don't use it from within other methods. + protected int next(int bits) { + return (int)(mix64(nextSeed()) >>> (64 - bits)); + } + + /** + * Returns a pseudorandom {@code int} value. + * + * @return a pseudorandom {@code int} value + */ + public int nextInt() { + return mix32(nextSeed()); + } + + /** + * Returns a pseudorandom {@code long} value. + * + * @return a pseudorandom {@code long} value + */ + public long nextLong() { + return mix64(nextSeed()); + } + + public double nextGaussian() { + // Use nextLocalGaussian instead of nextGaussian field + Double d = nextLocalGaussian.get(); + if (d != null) { + nextLocalGaussian.set(null); + return d.doubleValue(); + } + double v1, v2, s; + do { + v1 = 2 * nextDouble() - 1; // between -1 and 1 + v2 = 2 * nextDouble() - 1; // between -1 and 1 + s = v1 * v1 + v2 * v2; + } while (s >= 1 || s == 0); + double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s); + nextLocalGaussian.set(new Double(v2 * multiplier)); + return v1 * multiplier; + } + + static final BigInteger thePeriod = BigInteger.valueOf(1).shiftLeft(64); // Period is 2**64 + public BigInteger period() { return thePeriod; } + + // Within-package utilities + + /* + * Descriptions of the usages of the methods below can be found in + * the classes that use them. Briefly, a thread's "probe" value is + * a non-zero hash code that (probably) does not collide with + * other existing threads with respect to any power of two + * collision space. When it does collide, it is pseudo-randomly + * adjusted (using a Marsaglia XorShift). The nextSecondarySeed + * method is used in the same contexts as ThreadLocalRandom, but + * only for transient usages such as random adaptive spin/block + * sequences for which a cheap Rng suffices and for which it could + * in principle disrupt user-visible statistical properties of the + * main ThreadLocalRandom if we were to use it. + * + * Note: Because of package-protection issues, versions of some + * these methods also appear in some subpackage classes. + */ + + /** + * Returns the probe value for the current thread without forcing + * initialization. Note that invoking ThreadLocalRandom.current() + * can be used to force initialization on zero return. + */ + static final int getProbe() { + return UNSAFE.getInt(Thread.currentThread(), PROBE); + } + + /** + * Pseudo-randomly advances and records the given probe value for the + * given thread. + */ + static final int advanceProbe(int probe) { + probe ^= probe << 13; // xorshift + probe ^= probe >>> 17; + probe ^= probe << 5; + UNSAFE.putInt(Thread.currentThread(), PROBE, probe); + return probe; + } + + /** + * Returns the pseudo-randomly initialized or updated secondary seed. + */ + static final int nextSecondarySeed() { + int r; + Thread t = Thread.currentThread(); + if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) { + r ^= r << 13; // xorshift + r ^= r >>> 17; + r ^= r << 5; + } + else { + localInit(); + if ((r = (int)UNSAFE.getLong(t, SEED)) == 0) + r = 1; // avoid zero + } + UNSAFE.putInt(t, SECONDARY, r); + return r; + } + + // Serialization support + + private static final long serialVersionUID = -5851777807851030925L; + + /** + * @serialField rnd long + * seed for random computations + * @serialField initialized boolean + * always true + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("rnd", long.class), + new ObjectStreamField("initialized", boolean.class), + }; + + /** + * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it). + * @param s the stream + * @throws java.io.IOException if an I/O error occurs + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + + java.io.ObjectOutputStream.PutField fields = s.putFields(); + fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED)); + fields.put("initialized", true); + s.writeFields(); + } + + /** + * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}. + * @return the {@link #current() current} thread's {@code ThreadLocalRandom} + */ + private Object readResolve() { + return current(); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE; + private static final long SEED; + private static final long PROBE; + private static final long SECONDARY; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class tk = Thread.class; + SEED = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSeed")); + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + SECONDARY = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSecondarySeed")); + } catch (Exception e) { + throw new Error(e); + } + } +}