关于Java随机数

Java提供两种类型的随机数发生器

1.伪随机数发生器

伪随机数发生器采用特定的算法,将随机数种子seed转换成一系列的伪随机数。伪随机数依赖于seed的值,给定相同的seed值总是生成相同的随机数。伪随机数的生成过程只依赖CPU,不依赖任何外部设备,生成速度快,不会阻塞。

Java提供的伪随机数发生器有java.util.Random类和java.util.concurrent.ThreadLocalRandom类。

Random类采用AtomicLong实现,保证多线程的线程安全性,但正如该类注释上说明的,多线程并发获取随机数时性能较差。

多线程环境中可以使用ThreadLocalRandom作为随机数发生器,ThreadLocalRandom采用了线程局部变量来改善性能,这样就可以使用long而不是AtomicLong,此外,ThreadLocalRandom还进行了字节填充,以避免伪共享。

2.强随机数发生器

强随机数发生器依赖于操作系统底层提供的随机事件。强随机数生成器的初始化速度和生成速度都较慢,而且由于需要一定的熵累积才能生成足够强度的随机数,所以可能会造成阻塞。熵累积通常来源于多个随机事件源,如敲击键盘的时间间隔,移动鼠标的距离与间隔,特定中断的时间间隔等。所以,只有在需要生成加密性强的随机数据的时候才用它。

Java提供的强随机数发生器是java.security.SecureRandom类,该类也是一个线程安全类,使用synchronize方法保证线程安全,但jdk并没有做出承诺在将来改变SecureRandom的线程安全性。因此,同Random一样,在高并发的多线程环境中可能会有性能问题。

在linux的实现中,可以使用/dev/random和/dev/urandom作为随机事件源。由于/dev/random是堵塞的,在读取随机数的时候,当熵池值为空的时候会堵塞影响性能,尤其是系统大并发的生成随机数的时候,如果在随机数要求不高的情况下,可以去读取/dev/urandom来避免阻塞,方法是通过设置参数

-Djava.security.egd=file:/dev/urandom

但这样由于jdk的一个bug,实际上需要这样指定这个值

-Djava.security.egd=file:/dev/./urandom

原因是,在 sun.security.provider.SunEntries类,seedSource先读取系统参数java.security.egd,如果值为空的时候,读取java.security配置文件中的参数securerandom.source, 在通常情况下,就是读取参数securerandom.source,默认值是/dev/urandom。

sun.security.provider.SeedGenerator

final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM;
final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM;
    
if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) {
    try {
        instance = new NativeSeedGenerator();
        if (debug != null) {
            debug.println("Using operating system seed generator");
        }
    } catch (IOException e) {
        if (debug != null) {
            debug.println("Failed to use operating system seed "
                          + "generator: " + e.toString());
        }
    }
} else if (egdSource.length() != 0) {
    try {
        instance = new URLSeedGenerator(egdSource);
        if (debug != null) {
            debug.println("Using URL seed generator reading from "
                          + egdSource);
        }
    } catch (IOException e) {
        if (debug != null)
            debug.println("Failed to create seed generator with "
                          + egdSource + ": " + e.toString());
    }
}

在代码中可以看到当配置值是file:/dev/random或者file:/dev/urandom的时候,启用NativeSeedGenerator, 而在linux下的NativeSeedGenerator类的实现是这样的

class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator {
    NativeSeedGenerator() throws IOException {
        super();
    }
}

而URLSeedGenerator的默认构造方法是

URLSeedGenerator() throws IOException {
    this(SeedGenerator.URL_DEV_RANDOM);
}

也就是说哪怕设置了-Djava.security.egd=file:/dev/urandom,最后的结果一样是读取file:/dev/random,解决办法就是使用linux的多种路径表示法,即使用file:/dev/./urandom来绕过这个问题。

时间: 2024-10-12 10:04:10

关于Java随机数的相关文章

学习记录 java随机数的产生机制

java 随机数 一.在j2se里我们可以使用Math.random()方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以一定的数,比如说乘以100,他就是个100以内的随机,这个在j2me中没有. 二.在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,他可以产生随机整数.随机float.随机double,随机long,这个也是我们在j2me的程序里经常用的一个取随机数的方法. 三.在我们的System类

java随机数与数组的使用。

java随机数与数组的使用.    一:题目 二 代码:  public class Students {    int number;  // 学号    int State ;   // 年级    int Score ;    // 成绩         public Students(int number, int state, int score) {        super();        this.number = number;        State = state; 

Java随机数总结

随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串.数字.或者随即生成一个不定长度的数字.或者进行一个模拟的随机选择等等.Java提供了最基本的工具,可以帮助开发者来实现这一切. 一.Java随机数的产生方式 在Java中,随机数的概念从广义上将,有三种. 1.通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字. 2.通过Math.random()返回一个0到1之间的double值. 3.通过Random类来产生一个随机数,这个是专业的Ra

java 随机数的生成

生成10个不小于100000的6位数 public static void main(String[] args) { Random random = new Random(); for (int i=0;i<10;i++) { System.out.println("第=="+i+"个邀请码"+(random.nextInt(899999)+100000)); } } 结果: 第==0个邀请码536686 第==1个邀请码161397 第==2个邀请码685

(转)Java随机数

1 随机数的三种产生方式 本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示. 广义上讲,Java中的随机数的有三种产生方式: (01). 通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字.(02). 通过Math.random()返回一个0到1之间的double值.(03). 通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大. 1.1 第1种 通过System.currentTimeMillis()来获取

利用Java随机数计算圆周率π

一.理论篇 1. 数学公式 圆面积公式:π*r*r,其中π为圆周率,r为圆半径: 正方形面积公式:s*s,其中s为边长: 勾股定理:a*a + b*b = c*c,其中a/b分别为直角三角形的两个直角边,c为斜边. 2. 计算方法 考虑下图,边长为r的正方形内嵌了一个以r为半径的1/4圆. InsideCircle面积 = 以r为半径的圆面积 / 4 = π*r*r/4 正方形面积 = r*r 所以, InsideCircle面积 / 正方形面积 = (π*r*r/4) / (r*r) = π/

JAVA随机数集锦

Java产生随机数有两种常规方式 1.使用Math.random(),Math在java.lang.Math中 2.使用Random类,Random在java.util.Random中 Math.random()产生的是0~1之间的随机数,所以产生其他范围的数需要采用 (int)(Math.random() * 倍数) 这种格式完成操作 Random类需要如下声明 Random rd = new Random(); Random random = new Random(100); int i=r

java 随机数不重复

package test; import java.util.HashSet; import java.util.Random; public class Snippet { /** * 随机指定范围内N个不重复的数 * 在初始化的无重复待选数组中随机产生一个数放入结果中, * 将待选数组被随机到的数,用待选数组(len-1)下标对应的数替换 * 然后从len-2里随机产生下一个随机数,如此类推 * @param  max  指定范围最大值 * @param  min  指定范围最小值 * @p

Java随机数的使用

在java中实现随机数的类有两种,分别是和java.util.Math 和 java.util.Random 第一种:java.lang.Math.random() Math.random()方法创建的是[0.0,1.0)范围类的浮点数 示例代码: int i = 0; System.out.println("Math.random生成随机数!"); while (i < 3) { System.out.println("第" + i + "个数:&

java 随机数

java中一般有两种随机数,一个是Math中random()方法,一个是Random类. 一.Math.random() 随即生成0<x<1的小数. 实例:如何写,生成随机生成出0~100中的其中一个数呢? Math.random()返回的只是从0到1之间的小数,如果要50到100,就先放大50倍,即0到50之间,这里还是小数,如果要整数,就强制转换int,然后再加上50即为50~100. 最终代码:(int)(Math.random()*50) + 50 二.Random类 Random r