Java 随机数(Random VS SecureRandom)

生成随机数的几种方法

  • Math.random()一随机数
  • java.util.Random伪随机数(线性同余法生成)
  •  java.util.concurrent.ThreadLocalRandom 工具类
  • java.security.SecureRandom 真随机数
  •  Apache Commons-Lang 包中的 RandomStringUtils 类

Math.random():(产生[0,1)范围的double随机数)

源码

public static double random() {
        Random rnd = randomNumberGenerator;
        if (rnd == null) rnd = initRNG();
        return rnd.nextDouble();
    }


private static Random randomNumberGenerator;//伪随机数生成器

private static synchronized Random initRNG() {
        Random rnd = randomNumberGenerator;
        return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
    }

源码分析:当第一次调用Math.random()方法时,会生成伪随机数生成器randomNumberGenerator,之后再调用此方法将不再生成伪随机数生成器,而是继续沿用此伪随机数生成器。此种生成随机数的方式是线程安全的,但是在多线程下可能性能比较低。

java.util.Random工具类

基本算法:linear congruential pseudorandom number generator (LGC) 线性同余法伪随机数生成器
缺点:可预测

在注重信息安全的应用中,不要使用 LCG 算法生成随机数,请使用 SecureRandom

源码:

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

public Random(long seed) {
        if (getClass() == Random.class)
            this.seed = new AtomicLong(initialScramble(seed));
        else {
            // subclass might have overriden setSeed
            this.seed = new AtomicLong();
            setSeed(seed);
        }
    }

源码分析:Random类默认使用当前系统时钟作为种子,只要种子一样,产生的随机数也一样。种子确定,随机算法也确定,得出的随机数也是确定的。

 java.util.concurrent.ThreadLocalRandom 工具类

ThreadLocalRandom 是JDK 7之后继承至java.util.Random

源码:

public static ThreadLocalRandom current() {
        return localRandom.get();
    }

private static final ThreadLocal<ThreadLocalRandom> localRandom =
        new ThreadLocal<ThreadLocalRandom>() {
            protected ThreadLocalRandom initialValue() {
                return new ThreadLocalRandom();
            }
    };
//ThreadLocalRandom继承于Random
ThreadLocalRandom() {
        super();   //java.util.Random的构造方法
        initialized = true;
    }

使用:

package com.example.random;

import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalRandomTest {
	
	public static void main(String[] args) {
		new MyThread().start();
		new MyThread().start();
	}
}

class MyThread extends Thread{
	public void run(){
		for(int i=0;i<10;i++){
			System.out.println(Thread.currentThread().getName()+":"+ThreadLocalRandom.current().nextDouble());
		}
	}
}

源码分析:每一个线程有一个独立的随机数生成器,用于并发产生随机数,能够解决多个线程发生的竞争争夺,效率更高。ThreadLocalRandom 不是直接用 new 实例化,而是第一次使用其静态方法 current() 得到 ThreadLocal<ThreadLocalRandom> 实例,然后调用 java.util.Random 类提供的方法获得各种随机数。

 java.Security.SecureRandom(继承至java.util.Random)

使用:

//采用SecureRandom 生成6位验证码
private static String getRandom6() throws NoSuchAlgorithmException {
		
		SecureRandom random= SecureRandom.getInstance("SHA1PRNG");
		int verifiCode = (int)Math.ceil(random.nextFloat()*1000000);
		String verifiCodeStr = String.valueOf(verifiCode);
                //处理产生的随机数不及6位的情况
		while(verifiCodeStr.length()<6){
			verifiCode = (int)Math.ceil(random.nextFloat()*1000000);
			verifiCodeStr = String.valueOf(verifiCode);
		}
		return verifiCodeStr;
	}

SecureRandom提供加密的是强随机数生成器,种子是不可预知的,产生的随机数也是不确定。

从理论上来说计算机产生的随机数都是伪随机数,那么如何产生高强度的随机数?

答:产生高强度的随机数,有两个重要的因素:种子和算法。算法可以有很多种, 如何选择种子是非常关键的因素。如Random,它的种子是System.currentTimeMillis().所以它的随机数都是可以预测的。那么如何得到一个近似随机的种子?可以利用计算机收集的各种信息,如键盘输入时间,cpu时钟,内存使用状态,硬盘空闲空间,IO延时,进程的数量,线程数量等来得到以及近似随机的种子。如此,除了理论上有破解的可能,实际上基本没有被破解的可能。事实表明,现在高随机数的生成都是这样实现的。

 Apache Commons-Lang 包中的 RandomStringUtils 类

RandomStringUtils 类的实现上也是依赖了 java.util.Random 工具类

示例:

package com.example.random;

import org.apache.commons.lang.RandomStringUtils;

public class RandomStringUtilsTest {
	
	public static void main(String[] args) {
		
		//生成64位长度的数字字符串
		String result = RandomStringUtils.random(64,false,true);
		System.out.println("数字random:"+result);
		
		//生成64位的字母字符串
		result=RandomStringUtils.randomAlphabetic(64);
		System.out.println("字母random:"+result);
		
		//生成32位ASCII字符串
		result=RandomStringUtils.randomAscii(32);
		System.out.println("ASCII random:"+result);
		
		//根据指定字符生成32位随机字符串
		 result = RandomStringUtils.random(32, 0, 20, true, true, "qw32rfHIJk9iQ8Ud7h0X".toCharArray());
	     System.out.println("random = " + result);
				
	}

}

拓展:生成java随机字符串UUID。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值