patternjavaMinor
Random number generator initialisation
Viewed 0 times
randomnumberinitialisationgenerator
Problem
For a server-side Java application I want to have a random number generator. I'm using the ISAAC algorithm from Apache Commons Math 3 because it is both cryptographically strong and fast. I have written the following code to initialise the generator:
Basically I'm using a
Does this seem sensible?
public class ThreadLocalRandomGenerator {
private static ThreadLocal instances = new ThreadLocal<>();
public static RandomGenerator get() {
RandomGenerator generator = instances.get();
// Initialise new generator if needed.
if (generator == null) {
int[] seed = new int[256];
seed[0] = (int) (System.currentTimeMillis() & 0xffffffffL);
seed[1] = System.identityHashCode(new Object());
for (int i=2 ; i<256 ; i++) {
seed[i] = 0;
for (int j=0; j<32; j++) {
seed[i] |= (int) ((System.nanoTime() & 1L) << j);
}
}
System.out.println("Initialised random seed: " + Arrays.toString(seed));
// Create generator.
generator = new ISAACRandom(seed);
instances.set(generator);
// Warm up.
for (int i=0 ; i<1_000 ; i++) {
generator.nextLong();
}
}
return generator;
}
}Basically I'm using a
ThreadLocal to keep several generators around for use in threads, and I'm initialising each one using an array of integers generated from the least significant bits of nanoTime(). The reason for using 256 integers is because that's the internal size of the ISAACRandom class.Does this seem sensible?
Solution
For the most part, that's nice code. I can read it somewhat easily, and for the most part, it is logical, and structured.
There are a number of issues in your code, though, some style issues, and some functional issues.
First up, the style issues.
Using the existing libraries
There's a nice feature in ThreadLocal in Java8 that allows you to have a supplier for the structure. Consider a method like:
then your thread local can be created as:
Your main method can become a simple:
It is guaranteed that there will be an instance created for you on the first call from a thread.
Getting good seeding
Your seeding system is both complicated, and wrong.
If you are looking to have a special random generator that you feel out-performs the existing Java Random class, that's OK, but, it needs to be seeded right.
There are a few problems in your seeding that I can see. First up:
That can be simply an int cast. No need to mask off the bits:
Next up, is that computers have different precision in their nano clocks. A nano-second is far faster than the actual computer's time interrupt, so, it is common for computers to "step" significantly as it updates. The steps can be as much as 190 nanoseconds is where i have seen it....
... what that means, is that the results for all your seed values here may be the same:
In other words, you will have int values filled with either 0's or 1's... and no variations. Also, if the "step" for the nano-second clock happens to be an even number, it is possible that the low-order bit for your computer will always be the same value.... and all your seeds will be identical.
While the
I would simply use the following to seed your class:
Use the slower Random to seed your class, then let your class run with the rest.
Note, there is no real way to use the time systems in a computer to get random values... it's just not infused with enough entropy to be random, or predictability to be reliable.
There are a number of issues in your code, though, some style issues, and some functional issues.
First up, the style issues.
Using the existing libraries
There's a nice feature in ThreadLocal in Java8 that allows you to have a supplier for the structure. Consider a method like:
private static RandomGenerator buildGenerator() {
.....
}then your thread local can be created as:
private static ThreadLocal instances =
ThreadLocal.withInitial(ThreadLocalRandomGenerator::buildGenerator);Your main method can become a simple:
public static RandomGenerator get() {
return instances.get();
}It is guaranteed that there will be an instance created for you on the first call from a thread.
Getting good seeding
Your seeding system is both complicated, and wrong.
If you are looking to have a special random generator that you feel out-performs the existing Java Random class, that's OK, but, it needs to be seeded right.
There are a few problems in your seeding that I can see. First up:
seed[0] = (int) (System.currentTimeMillis() & 0xffffffffL);That can be simply an int cast. No need to mask off the bits:
seed[0] = (int)System.currentTimeMillis();Next up, is that computers have different precision in their nano clocks. A nano-second is far faster than the actual computer's time interrupt, so, it is common for computers to "step" significantly as it updates. The steps can be as much as 190 nanoseconds is where i have seen it....
... what that means, is that the results for all your seed values here may be the same:
seed[i] |= (int) ((System.nanoTime() & 1L) << j);In other words, you will have int values filled with either 0's or 1's... and no variations. Also, if the "step" for the nano-second clock happens to be an even number, it is possible that the low-order bit for your computer will always be the same value.... and all your seeds will be identical.
While the
Random class in Java may be slower than you want, you can at least use it to seed the faster ISAAC algorithm.I would simply use the following to seed your class:
Random rand = new Random();
int seed[] = rand.ints(256).toArray();Use the slower Random to seed your class, then let your class run with the rest.
Note, there is no real way to use the time systems in a computer to get random values... it's just not infused with enough entropy to be random, or predictability to be reliable.
Code Snippets
private static RandomGenerator buildGenerator() {
.....
}private static ThreadLocal<RandomGenerator> instances =
ThreadLocal.withInitial(ThreadLocalRandomGenerator::buildGenerator);public static RandomGenerator get() {
return instances.get();
}seed[0] = (int) (System.currentTimeMillis() & 0xffffffffL);seed[0] = (int)System.currentTimeMillis();Context
StackExchange Code Review Q#108606, answer score: 8
Revisions (0)
No revisions yet.