I'm using an OAuth library that calls new Random().nextLong() to generate nonces, however it generates the same nonce on asynchronous calls. I've narrowed it down to threading Random.nextLong() to returning the same exact number every so often.
Does anyone know if this is a known limitation of Java? If so, does anyone know of a thread safe operation?
EDIT: I'm using Java 1.6
EDIT: This is a small program I made to test out what was going on in my larger app. I ran this several times and more often that it should, it was coming up with the same random number when the time was the same. Please excuse my quick programming.
public class ThreadedRandom {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new ThreadedRandom().run();
}
private RandomNumberGenerator _generator;
public ThreadedRandom()
{
_generator = new RandomNumberGenerator();
}
public void run()
{
Runnable r = new Runnable() {
@Override public void run() {
System.out.println(System.currentTimeMillis()+"\t"+_generator.gen());
}
};
Thread t1, t2;
t1 = new Thread(r);
t2 = new Thread(r);
t1.start();
t2.start();
}
private class RandomNumberGenerator {
Random random;
public RandomNumberGenerator()
{
random = new Random();
}
public Long gen() {
return new Random().nextLong()开发者_如何学编程;
}
}
}
You might not want to be creating a new instance of Random each time. Rather have a global one.
Random numbers are not truly random, they are "pseudo-random" and they require a "seed" value. If the same seed is used, the same sequence of pseudo-random values will be generated.
When you create a new instance of the Random class, you can either specify a seed yourself or let the system choose one for you. In Java, the default seed is the current system time in milliseconds, see:
http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#Random%28%29
If you create Random objects within the same millisecond, they will have the same sequence of values.
Normally you want to share a single Random object among all the different threads to avoid this kind of problem.
Although I'm not immediately familiar with the underlying implementation of Random
, if I had to guess I would imagine that calling new Random()
delegates to new Random(System.currentTimeMillis())
. That gives a reasonably different Random
sequence for Randoms instantiated at different times.
However, since you've mentioned asynchronous calls, it's possible your calls are both executing at essentially the same time. That means that when the threads invoke the library, they're both hitting the new Random()
call at the same time, and the Randoms get identical seeds, so they will produce the same random sequence.
You should really be using SecureRandom since you are using this for something related to security.
I thought Random was not thread safe, but it is. You should only get Random producing the same number every 2^48 values.
As has been noted, Java 1.4 and previous had a bug where two Randoms could get the same seed. I suggest you use Java 6, or set the seed to be unique yourself.
You should also note that Random uses a 48-bit seed. This means it will repeat after 2^48 values and produce only 2^48 unique long values. If this is a problem for you, use a SecureRandom which is much more expensive, but will produce all possible long values.
精彩评论