6
votes

I'm initializing two random number generators on two threads almost simultaneously and I want the two generators behaves completely different. I will call Random.nextInt(7) on two generators one right after another very often. Using System.currentTimeMillis() is not a good idea because it looks like my computer is so fast that there's a large chance that the number I get from the two generators are the same. So is there any way to config the Random so that though they are called one right after another, they still behave differently? I want the solution to be cross-platform compatible so any platform-specific idea such as read from /dev/random is not acceptable. Thanks for help.

5

5 Answers

7
votes

One way: Seed each Random instance with a UUID (GUID) converted (hashed? but probably not just a cast) to a long.

Other answers suggest using nanoTime, which may be suitable depending on the speed of the hardware, but I prefer the UUID route.

1
votes

You can use System.nanoTime() which will reduce the likelihood that both threads with have the same seed.

Or create a thread-safe utility class to get for you the random number object while ensuring that it uses a different seed for each new instance.

Also, you can assign for each thread a numeric id as the thread name and append it to the seed

1
votes

You can use SecureRandom to generate seeds for your two random number generators. It uses a service provider infrastructure which can use platform-specific entropy sources, so on systems where it is available, you'll likely get entropy from /dev/random without having to worry about it in your code. The UUID mentioned in another answer is generated from such a source, at least in OpenJDK 7.6.

That said, notice that since Java 7, the preferred way to use PRNGs in multiple threads is ThreadLocalRandom. I'm not sure but it seems to me that the main goal here is avoiding synchronization overhead, not seeding issues. At least in OpenJDK 7.6, the constructor uses the default Random constructor, which in turn uses the high-resolution system time (given in nanoseconds, but not neccessarily with that actual resolution), combined with the current value of a static variable. The latter ensures different seeds even for instances created during the same tick of the system clock, so your original problem should be gone even when simply constructing Random instances using the default constructor.

This uniquification was introduced in 2010, in response to bug report #6937857. The report was reported against Java 7 and was also fixed in Java 7, but according to the mercurial repository, this change should have been first included in the jdk7-b94 release.

0
votes

You can use System.nanoTime(), instead of System.currentTimeMillis().

Just delay the creation of the second thread by 30ms, that will cause nanoTime() to be randomly differnet from nanoTime() of thread1

So there is one practical view of your question, for this view nanoTime() i consider sufficient.

The other view, is a more theoretical for military safe enryption. There you want to use special hardware that use physical randomness (random registers). But that is not your intention.

0
votes

Don't do anything. It works!

This is the code of java.util.Random:

public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

As the name says, the seedUniquifier makes the seed unique. It works both in a single thread and multithreaded:

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;
    }
}