Concurrent calls to new Random() not random enough

Martin Buchholz martinrb at google.com
Wed Mar 24 02:17:20 UTC 2010


[+fy, jeremymanson]

Here's a much better test case,
and a proposed fix:

http://cr.openjdk.java.net/~martin/webrevs/openjdk7/RandomSeedCollisions

This adds some initialization overhead, but also removes some
since
new Random()
no longer invokes a synchronized method.

----
import java.util.*;

public class RandomSeed {
    public static void main(String[] args) throws Throwable {
        class RandomCollector implements Runnable {
            long[] randoms = new long[1<<22];
            public void run() {
                for (int i = 0; i < randoms.length; i++)
                    randoms[i] = new Random().nextLong();
            }};
        final int threadCount = 2;
        List<RandomCollector> collectors = new ArrayList<RandomCollector>();
        List<Thread> threads = new ArrayList<Thread>();
        for (int i = 0; i < threadCount; i++) {
            RandomCollector r = new RandomCollector();
            collectors.add(r);
            threads.add(new Thread(r));
        }
        for (Thread thread : threads)
            thread.start();
        for (Thread thread : threads)
            thread.join();
        int collisions = 0;
        HashSet<Long> s = new HashSet<Long>();
        for (RandomCollector r : collectors) {
            for (long x : r.randoms) {
                if (s.contains(x))
                    collisions++;
                s.add(x);
            }
        }
        System.out.printf("collisions=%d%n", collisions);
    }
}


On Tue, Mar 23, 2010 at 15:50, Martin Buchholz <martinrb at google.com> wrote:
> Hi Sherman,
>
> This is a bug report (sorry, no fix this time)
>
> Synopsis: Concurrent calls to new Random() not random enough
> Description:
> new Random() promises this:
>    /**
>     * 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.
>     */
>
> but if there are concurrent calls to new Random(), it does not
> do very well at fulfilling its contract.
>
> The following program should print out a number much closer to 0.
>
> import java.util.*;
>
> public class RandomSeed {
>    public static void main(String[] args) throws Throwable {
>        class RandomCollector implements Runnable {
>            int[] randoms = new int[1<<21];
>            public void run() {
>                for (int i = 0; i < randoms.length; i++)
>                    randoms[i] = new Random().nextInt();
>            }};
>        final int threadCount = 2;
>        List<RandomCollector> collectors = new ArrayList<RandomCollector>();
>        List<Thread> threads = new ArrayList<Thread>();
>        for (int i = 0; i < threadCount; i++) {
>            RandomCollector r = new RandomCollector();
>            collectors.add(r);
>            threads.add(new Thread(r));
>        }
>        for (Thread thread : threads)
>            thread.start();
>        for (Thread thread : threads)
>            thread.join();
>        int collisions = 0;
>        HashSet<Integer> s = new HashSet<Integer>();
>        for (RandomCollector r : collectors) {
>            for (int x : r.randoms) {
>                if (s.contains(x))
>                    collisions++;
>                s.add(x);
>            }
>        }
>        System.out.println(collisions);
>    }
> }
> ---
> ==> javac -source 1.6 -Xlint:all RandomSeed.java
> ==> java -esa -ea RandomSeed
> 876
>



More information about the core-libs-dev mailing list