--- jsr166/src/main/java/util/Random.java 2007/01/30 03:46:41 1.19 +++ jsr166/src/main/java/util/Random.java 2013/01/16 19:01:22 1.32 @@ -1,20 +1,41 @@ /* - * %W% %E% + * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. */ package java.util; import java.io.*; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.IntStream; +import java.util.stream.Streams; + import sun.misc.Unsafe; /** * An instance of this class is used to generate a stream of * pseudorandom numbers. The class uses a 48-bit seed, which is * modified using a linear congruential formula. (See Donald Knuth, - * The Art of Computer Programming, Volume 3, Section 3.2.1.) + * The Art of Computer Programming, Volume 2, Section 3.2.1.) *

* If two instances of {@code Random} are created with the same * seed, and the same sequence of method calls is made for each, they @@ -32,8 +53,19 @@ import sun.misc.Unsafe; *

* Many applications will find the method {@link Math#random} simpler to use. * + *

Instances of {@code java.util.Random} are threadsafe. + * However, the concurrent use of the same {@code java.util.Random} + * instance across threads may encounter contention and consequent + * poor performance. Consider instead using + * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded + * designs. + * + *

Instances of {@code java.util.Random} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} to + * get a cryptographically secure pseudo-random number generator for use + * by security-sensitive applications. + * * @author Frank Yellin - * @version %I%, %G% * @since 1.0 */ public @@ -48,17 +80,32 @@ class Random implements java.io.Serializ */ private final AtomicLong seed; - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; /** * Creates a new random number generator. This constructor sets * the seed of the random number generator to a value very likely * to be distinct from any other invocation of this constructor. */ - public Random() { this(++seedUniquifier + System.nanoTime()); } - private static volatile long seedUniquifier = 8682522807148012L; + public Random() { + this(seedUniquifier() ^ System.nanoTime()); + } + + private static long seedUniquifier() { + // L'Ecuyer, "Tables of Linear Congruential Generators of + // Different Sizes and Good Lattice Structure", 1999 + for (;;) { + long current = seedUniquifier.get(); + long next = current * 181783497276652981L; + if (seedUniquifier.compareAndSet(current, next)) + return next; + } + } + + private static final AtomicLong seedUniquifier + = new AtomicLong(8682522807148012L); /** * Creates a new random number generator using a single {@code long} seed. @@ -74,8 +121,17 @@ class Random implements java.io.Serializ * @see #setSeed(long) */ public Random(long seed) { - this.seed = new AtomicLong(0L); - setSeed(seed); + if (getClass() == Random.class) + this.seed = new AtomicLong(initialScramble(seed)); + else { + // subclass might have overriden setSeed + this.seed = new AtomicLong(); + setSeed(seed); + } + } + + private static long initialScramble(long seed) { + return (seed ^ multiplier) & mask; } /** @@ -98,9 +154,8 @@ class Random implements java.io.Serializ * @param seed the initial seed */ synchronized public void setSeed(long seed) { - seed = (seed ^ multiplier) & mask; - this.seed.set(seed); - haveNextNextGaussian = false; + this.seed.set(initialScramble(seed)); + haveNextNextGaussian = false; } /** @@ -132,8 +187,8 @@ class Random implements java.io.Serializ long oldseed, nextseed; AtomicLong seed = this.seed; do { - oldseed = seed.get(); - nextseed = (oldseed * multiplier + addend) & mask; + oldseed = seed.get(); + nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); } @@ -158,11 +213,11 @@ class Random implements java.io.Serializ * @since 1.1 */ public void nextBytes(byte[] bytes) { - for (int i = 0, len = bytes.length; i < len; ) - for (int rnd = nextInt(), - n = Math.min(len - i, Integer.SIZE/Byte.SIZE); - n-- > 0; rnd >>= Byte.SIZE) - bytes[i++] = (byte)rnd; + for (int i = 0, len = bytes.length; i < len; ) + for (int rnd = nextInt(), + n = Math.min(len - i, Integer.SIZE/Byte.SIZE); + n-- > 0; rnd >>= Byte.SIZE) + bytes[i++] = (byte)rnd; } /** @@ -184,7 +239,7 @@ class Random implements java.io.Serializ * value from this random number generator's sequence */ public int nextInt() { - return next(32); + return next(32); } /** @@ -235,11 +290,11 @@ class Random implements java.io.Serializ * successive calls to this method if n is a small power of two. * * @param n the bound on the random number to be returned. Must be - * positive. + * positive. * @return the next pseudorandom, uniformly distributed {@code int} * value between {@code 0} (inclusive) and {@code n} (exclusive) * from this random number generator's sequence - * @exception IllegalArgumentException if n is not positive + * @throws IllegalArgumentException if n is not positive * @since 1.2 */ @@ -299,11 +354,11 @@ class Random implements java.io.Serializ * * @return the next pseudorandom, uniformly distributed * {@code boolean} value from this random number generator's - * sequence + * sequence * @since 1.2 */ public boolean nextBoolean() { - return next(1) != 0; + return next(1) != 0; } /** @@ -390,7 +445,7 @@ class Random implements java.io.Serializ */ public double nextDouble() { return (((long)(next(26)) << 27) + next(27)) - / (double)(1L << 53); + / (double)(1L << 53); } private double nextNextGaussian; @@ -444,22 +499,26 @@ class Random implements java.io.Serializ synchronized public double nextGaussian() { // See Knuth, ACP, Section 3.4.1 Algorithm C. if (haveNextNextGaussian) { - haveNextNextGaussian = false; - return nextNextGaussian; - } else { + haveNextNextGaussian = false; + return nextNextGaussian; + } else { double v1, v2, s; - do { + do { v1 = 2 * nextDouble() - 1; // between -1 and 1 - v2 = 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); - nextNextGaussian = v2 * multiplier; - haveNextNextGaussian = true; - return v1 * multiplier; + } while (s >= 1 || s == 0); + double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s); + nextNextGaussian = v2 * multiplier; + haveNextNextGaussian = true; + return v1 * multiplier; } } + public IntStream ints() { + return Streams.generateInt(this::nextInt); + } + /** * Serializable fields for Random. * @@ -485,9 +544,9 @@ class Random implements java.io.Serializ ObjectInputStream.GetField fields = s.readFields(); - // The seed is read in as {@code long} for - // historical reasons, but it is converted to an AtomicLong. - long seedVal = (long) fields.get("seed", -1L); + // The seed is read in as {@code long} for + // historical reasons, but it is converted to an AtomicLong. + long seedVal = fields.get("seed", -1L); if (seedVal < 0) throw new java.io.StreamCorruptedException( "Random: invalid seed"); @@ -500,12 +559,12 @@ class Random implements java.io.Serializ * Save the {@code Random} instance to a stream. */ synchronized private void writeObject(ObjectOutputStream s) - throws IOException { + throws IOException { // set the values of the Serializable fields ObjectOutputStream.PutField fields = s.putFields(); - // The seed is serialized as a long for historical reasons. + // The seed is serialized as a long for historical reasons. fields.put("seed", seed.get()); fields.put("nextNextGaussian", nextNextGaussian); fields.put("haveNextNextGaussian", haveNextNextGaussian); @@ -521,7 +580,7 @@ class Random implements java.io.Serializ try { seedOffset = unsafe.objectFieldOffset (Random.class.getDeclaredField("seed")); - } catch (Exception ex) { throw new Error(ex); } + } catch (Exception ex) { throw new Error(ex); } } private void resetSeed(long seedVal) { unsafe.putObjectVolatile(this, seedOffset, new AtomicLong(seedVal));