Java 随机数(Random VS SecureRandom)

本文深入探讨了五种随机数生成方法:Math.random(), java.util.Random, java.util.concurrent.ThreadLocalRandom, java.security.SecureRandom及Apache Commons Lang包的RandomStringUtils类。详细分析了每种方法的原理、使用场景及优缺点。

生成随机数的几种方法

  • 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。

<think> 首先,用户的问题是基于之前的对话历史,但在这个场景中,用户引用了几个来源,我需要根据这些引用来回答问题。用户的问题是:“我想查找在Java中使用Random类生成double类型随机数的方法 请问Java中使用Random类生成double类型随机数的方法”。 从引用的内容中: - 引用[1]提到Random类的nextInt()方法,但用户问的是double类型。 - 引用[2]说“导入Random类”,但没有具体方法。 - 引用[3]提到Random类可以生成随机整数、长整数、浮点数等,包括生成随机浮点数。 - 引用[4]提到Math.random()生成double,但用户指定了Random类。 具体到引用[3]:"介绍Random类的所有使用方法,包括生成随机整数、随机长整数、随机浮点数、随机布尔值以及随机字节等。" 所以,Random类应该有一个方法生成double类型随机数。 在Java中,Random类有nextDouble()方法,用于生成0.0到1.0之间的double值。 确认引用: - 引用[1]: 提到Random.nextInt(),但不涉及double。 - 引用[2]: 只说导入Random类,没具体方法。 - 引用[3]: 明确说包括生成随机浮点数。 - 引用[4]: 提到Math.random(),但用户要Random类。 所以,我应该基于引用[3]来回答,因为它提到Random类生成随机浮点数。 用户的问题直接问“使用Random类生成double类型随机数的方法”,所以我需要给出具体代码示例。 回答结构: - 使用中文回答。 - 结构清晰,逐步解决问题。 - 确保真实性:在Java中,使用java.util.Random类的nextDouble()方法。 - 添加代码示例。 - 在引用段落末尾添加引用标识,如[^n]。 - 生成相关问题。 系统指令要求生成相关问题。 最终回答应包括: 1. 解释方法。 2. 代码示例。 3. 引用标识。 4. 相关问题。 代码格式:使用```java```包裹代码块。 关于引用:在相关部分添加[^3],因为引用[3]提到Random类生成浮点数。 </think>在Java中,使用`java.util.Random`类生成double类型的随机数非常简单。该类提供了`nextDouble()`方法,可以生成一个介于0.0(包含)1.0(不包含)之间的伪随机double值。以下是详细步骤示例代码,帮助您逐步实现。 ### 步骤说明 1. **导入Random类**:首先,在代码中导入`java.util.Random`包。 2. **创建Random实例**:通过`new Random()`实例化Random对象。 3. **调用nextDouble()方法**:使用`nextDouble()`生成随机double值。 4. **扩展范围(可选)**:如果需要指定范围(如生成0.0到100.0之间的随机数),可以通过数学运算(如乘以倍数)实现。 ### 代码示例 以下是一个完整的Java示例,展示如何生成double类型随机数: ```java import java.util.Random; // 导入Random类 public class RandomDoubleExample { public static void main(String[] args) { // 步骤1: 创建Random对象 Random random = new Random(); // 步骤2: 生成一个0.0到1.0之间的随机double值 double randomValue1 = random.nextDouble(); System.out.println("生成的随机值 (0.0到1.0): " + randomValue1); // 步骤3(可选): 生成指定范围的随机double值,例如0.0到100.0 double randomValue2 = random.nextDouble() * 100; System.out.println("生成的随机值 (0.0到100.0): " + randomValue2); } } ``` ### 输出示例 运行上述代码,可能的输出如下(实际值每次运行不同): ``` 生成的随机值 (0.0到1.0): 0.872465 生成的随机值 (0.0到100.0): 56.342198 ``` ### 注意事项 - `nextDouble()`方法基于伪随机数生成器,结果在多次运行中可能不同,但可通过设置种子(如`Random random = new Random(123L)`)实现可重现性[^3]。 - 如果需要更高质量的随机数(如加密场景),建议使用`java.security.SecureRandom`类代替Random类[^4]。 - 与`Math.random()`(返回0.0到1.0的double)相比,Random类的`nextDouble()`更灵活,支持范围扩展种子控制[^1][^3]。 通过以上方法,您可以轻松在Java中生成double类型随机数Random类还支持其他随机类型(如整数、布尔值),使其成为生成伪随机数的强大工具[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值