本篇将解答下面内容:
- java中创建随机数的两种方法
- 为什么说Random是伪的?
- Random类继承关系
- 为什么需要随机因子?
一、java中创建随机数的两种方式
方式一:
double r= Math.random();
方式二:
Random random=new Random();
其实方式都只有一种,就是方式二。因为方式一底层也是用方式二来实现的。见源码:
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
//这里可以看出,Math类也是通过创建Random对象,通过调用Random对象的nextDouble方法获取随机数的
static final Random randomNumberGenerator = new Random();
}
Random
随机数的产生,是根据一定的算法------线性同余公式(linear congruential formula)产生的。下面就是线性同余公式的实现
private final AtomicLong seed;
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
//next方法也许是Random类的核心了吧
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
/**
* 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());
}
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}
public double nextXXX(){
{
//do stuff
}
二、为什么说Random是伪的?
因为,java中随机数的产生是根据是一定的算法产生的,因此有一定的规律。正如上面代码,只要两个Random实例的种子
(种子)一样,那么他们的第n次nextXXX
就一样。例子:
double r= Math.random();
Random random=new Random(1l);
Random random1=new Random(1l);
System.out.println(random.nextInt());
System.out.println(random1.nextInt());
System.out.println(random.nextDouble());
System.out.println(random1.nextDouble());
结果:
-1155869325
-1155869325
0.10047321632624884
0.10047321632624884
三、Random类继承关系
正如jdk里面的注释所说, java.util.Random
是线程安全的,然而在多线程的情况下性能就差了。因此,在多线程环境下,建议使用java.util.concurrent.ThreadLocalRandom
。
java.util.Random
不是加密安全的。Java自带的随机数函数是很容易被黑客破解的,因为黑客可以通过获取一定长度的随机数序列来推出你的seed,然后就可以预测下一个随机数。因此,在安全性敏感的应用中,建议使用ava.security.SecureRandom
。
四、为什么需要随机因子
当见到了Random源码,就知道为什么Random需要随机因子了。因为它那个线性同余公式需要一个48-bit 种子。
五、参考文献
为什么说Java中的随机数都是伪随机数?
jdk源码