Java中Random为什么需要随机因子?


本篇将解答下面内容:

  • 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源码

发布了231 篇原创文章 · 获赞 93 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wobushixiaobailian/article/details/86158702