精华内容
下载资源
问答
  • 随机数,相信大家都不陌生,网上有很多生成随机数的小工具。直观来看,随机数就是一串杂乱无章的数字、字母、以及符号的组合, 比如pSTkKIiZMOlDxOgwpIQGdlZwrJCRiHRK。但随机数真的就随机吗?真的就无法预测吗?什么...

    随机数,相信大家都不陌生,网上有很多生成随机数的小工具。直观来看,随机数就是一串杂乱无章的数字、字母、以及符号的组合, 比如pSTkKIiZMOlDxOgwpIQGdlZwrJCRiHRK。但随机数真的就随机吗?真的就无法预测吗?什么场景下可以用什么方式来生成随机数呢? 这篇文章将为大家介绍随机数的类型,在程序中如何使用随机数,以及随机数在密码学中使用场景。希望能尽量地将在开发过程中需要用到的随机数知识都收纳在这里,方便大家进行查阅!

    随机数的类型

    在知乎上看到过一个说法,认为这个世界没有真正意义上的随机,比如扔骰子。如果能算对扔出时的转速、方向,并测出空气中的阻力,桌面的阻尼系数,骰子的质量 等等因素,那么就有机会算出骰子落地时的点数。我猜想赌神大概率也是基于这种原理吧。物理科学上是有“真正”意义的随机的,那就是量子力学的不可测原理。它是由德国著名物理学家海森堡在1927年发表的论文《论量子理论运动学与力学的物理内涵》中提出来的。不是特别理解其中的内容,但是从字面上简单的理解,就是对于微观粒子,它的速度和位置不能准确测量,当对其中一个物理量测量得越准确时,另一个物理量就越模糊。

    从编程角度看,我们的随机数生成器分为两种大类型,一种是真随机数生成器,一种是伪随机数生成器。

    真随机数生成器 TRNG - True Random Number Generator

    前面说了实际上基本没有真正意义随机,那程序和算法本身就更加不能产生真随机,但是我们可以想办法迂回地产生统计意义上的真随机。比如Linux内核的随机数发生器: Linux维持一个熵池,不断地收集非确定性的事件,比如时钟,鼠标的移动,键盘的敲击, IO的响应时间,磁盘的速度,wifi的强弱,内存的变化等等,然后基于一定的算法给出一个数。

    伪随机数生成器 PRNG - Pseudo Random Number Genrator

    如果需要快速生成大量的随机数,那么真随机数生成器可能由于收集不到那么多的随机事件而产生阻塞行为。在不需要那么高安全级别的随机数需求下,我们可以采用伪随机数生成器来生成随机数。伪随机数生成器一般是基于一个给定的初始值,也就是种子 - seed,用一定的算法来算出一个数。且算法内部维持一个内部状态,每次生成一个新的随机数,这个值都会跟着变化,这样就能产生不一样的随机数来。常见的伪随机数生成器的算法有:

    • 线性同余法 - Linear Congruential Generator (简称LCG)
    • 马特赛特旋转演算法 - Mersenne Twister.

    Java中的Random() 用的就是线性同余法。线性同余方法是目前应用广泛的伪随机数生成算法,其基本思想是通过对前一个数进行线性运算并取模从而得到下一个数,递归公式为:

    7220b442c371f201d886f0cb24b7e5f4.png

    其中A,B,M是产生器所用到的常量

    随机数的使用

    真随机数

    我们可以通过下面这个命令得到操作系统内核提供的外部熵随机数生成器:

    λ head -c 32 /dev/random | openssl enc -base64zLvAZ2vfFTUQ+ENPLdbG2F8B3wv86LM9X2s3DeymN28=

    这个命令将会从Linux内核的熵池中读取一个32位的随机数,并用64进制展示出来。我们也可以选择用数字的形式展示出来:

    λ cat /dev/random| tr -dc '0-9' | fold -w 10| head -n 40231488700459984660476294110514199097655

    上面这个命令从熵池中4个10位的随机数,并用0-9展示出来。

    但用这个命令的时候要小心,由于熵池中的值通过记录系统的随机事件得来的,那么就有可能有用完的时候,那么这时这个命令就会阻塞在这里,直到有系统随机事件进到熵池中才会继续。这样对程序来说不是很友好,于是操作系统的随机数生成器一般都提供另外一个工具,在熵池的随机事件用完之后,能用伪随机算法产生一个随机数给你:

    λ cat /dev/urandom| tr -dc 'a-zA-Z0-9' | fold -w 10| head -n 4EK0Z3g49BycsziDZeWtOEhHu30IcM4PyDyY47Ah5

    Golang的内置随机数生成器rand就是基于 /dec/urandom来实现的。

    开发中常见的随机数生成器

    这里我们以Java语言为例,介绍一下常见的随机数生成器的用法。

    • Random()

    首先一起来看一下这个最常见的Random. Random实现了基于线性同余法的伪随机数生成器,其构造函数接收作为种子的参数seed,如果不给定seed,则默认采用当前时间戳作为种子。 下面的函数可以生成指定位数的随机字母串:

    public static String ALPHA = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";   public static String generate_alphabetic_using_Random(int length) {        Random random = new Random();        StringBuffer buffer = new StringBuffer();        int bound = ALPHA.length();        for(int i=0; i< length; i++){            buffer.append(ALPHA.charAt(random.nextInt(bound)));        }        return buffer.toString();    }
    • RandomStringUtil

    如果大家只是偶尔需要用到随机字符串,不要什么特别的随机字符集的话,那么可以用Apache Common提供的RandomStringUtil 辅助类,可以方便地生成常见的随机字符串:

        public static String generate_alphabetic_using_RandomUtils(int length){       return RandomStringUtils.randomAlphabetic(length);    }

    作为一款良心包,Apache Common一般都会有一系列的实现方法可供选择,比如:

    54eff4c7b73596cba80decf1c3451aee.png
    • Math.random()如果要生成的是随机数,那么也可以使用Math类的random方法来实现。 System.out.println("--- using Math.random ---");
      for (int i = 0; i < 20; i++) {
      System.out.println(Math.random() * 100);
      }这里提一下,Math.random()的实现其实是调用了Random.nextDouble()的,使用它本质上是Random的一个包装

    随机数生成的并发性能问题

    前面我们提到Random随机数生成器里面维护着一个内部状态,每次随机数的生成这个内部状态都需要跟着改变,这样才能生成不同的随机数。我们跟一下源码就可以发现Random的seed是一个AtomicLong型,当计算下一个随机数的时候,会用到CompareAndSwap (CAS) 操作,如果切换失败的话,那么就重新计算下一个随机数:

       private final AtomicLong seed;       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));    }

    当并发有很多个线程都在获取下一个种子的时候,那么性能就会降下来,因为有很多failed-retry的。

    有坑就填坑! 既然有并发问题,那么我们就来ThreadLocal吧。Java内置了一个ThreadLocalRandom类,这个类继承了Random, 但是每一个线程都有一个ThreadLocal的seed,这样当并发计算next()的时候,CAS操作就不会有太多冲突了。ThreadLocalRandom的用法也是很简单的, 跟Random基本一致:

    public static String ALPHA = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";   public static String generate_alphabetic_using_ThreadLocalRandom(int length) {        Random random = ThreadLocalRandom.current();        StringBuffer buffer = new StringBuffer();        int bound = ALPHA.length();        for(int i=0; i< length; i++){            buffer.append(ALPHA.charAt(random.nextInt(bound)));        }        return buffer.toString();    }

    Random真的随机吗?

    我们来看下面这个用法:

      public static void sameSeed_generate_sameResult(long seed){        Random random1 = new Random(seed);        Random random2 = new Random(seed);        System.out.println(String.format("random1: %d, random2: %d", random1.nextInt(100), random2.nextInt(100)));    }​  public static void main(String[] args) {        System.out.println("--- sameSeed_generate_sameResult ---");        sameSeed_generate_sameResult(3000);    }

    你种子相同的Random生成的随机数是一样的:

    --- sameSeed_generate_sameResult ---random1: 17, random2: 17

    这也可以理解,初始值seed一样,算法一样,那么生成的结果也会是一样的。 这种情况对于大多数需要随机数的场景来说,也是可以接受的。但是对于安全要求比较高的场景,比如密码学中,这样就容易被人攻击猜到随机数,比如Java的Random(),默认的种子是当前时间戳, 同余算法是公开的nextseed = (oldseed * multiplier + addend) & mask;,算法中的A,B,M这三个常量也是固定的

        private static final long multiplier = 0x5DEECE66DL;    private static final long addend = 0xBL;    private static final long mask = (1L << 48) - 1;

    那么就有可能通过穷举一段时间内的所有seed,来求得随机数。

    还是那句话,有坑填坑!

    Java在security这个包里面提供了一个SecureRandom的类,以操作系统随机数生成器生成seed,再用Hash算法SHA1计算出摘要值作为最终结果。这样以操作系统随机数生成器生成seed 加上 一动有蝴蝶效应的 hash算法,计算出来的随机数更加能以被猜测出来。

        public static String generate_alphaString_using_SecureRandom(int length)        throws NoSuchAlgorithmException {//        Random random =new SecureRandom(); // default is SHA1PRNG        Random random =SecureRandom.getInstance("SHA1PRNG");        StringBuffer buffer = new StringBuffer();        int bound = ALPHA.length();        for(int i=0; i< length; i++){            buffer.append(ALPHA.charAt(random.nextInt(bound)));        }        return buffer.toString();    }

    用SecureRandom的注意事项

    前面我们说到真随机数的生成有两个方式,一个是/dev/random, 一个是/dev/urandom,不同的是/dev/random是阻塞的。而SHA1PRNG 会根据JRE里面的配置选择/dec/random 还是/dev/urandom,如果里面配置的是securerandom.source=file:/dev/random, 那么当操作系统的熵池用完之后,你的程序在求随机数的时候会被阻塞住,直到有随机事件到来。据说Tomcat里面就是使用SecuredRandom.getInstance('SHA1PRNG') 的,使用有时初始化很慢很慢。具体的解决方案就是, 打开$JAVA_PATH/jre/lib/security/java.security , 确保里面的securerandom.source配置为file:/dev/random .

    随机数的应用场景

    随机数的应用场景有很多,尤其是在密码学应用中,基本上大部分的密码学算法实际应用中都用到了随机数。下面列举一些常见的使用场景:

    • UUID: UUID v4 里面是由 6个固定位 + 122个随机数来组成的
    • 密码学算法应用中用到的随机数密钥:对称加密算法,公开密钥算法,Message Authentication Code算法都会用到密钥,而大部分情况下,密钥就是随机数IV: 块密码加密中CBC迭代模式会用随机数作为IV,这样可以使得相同的明文加密出来的密文都不同,提高密码猜测的难度nonce: 块密码算法的CTR模式后用到noncesalt: 基于口令的加密算法会用到,很多Hash算法也会用到随机数作为盐

    以上内容介绍了随机数的类型,随机数的使用,重点是在Java里面是怎么用的,以及多线程开发下的性能,密码学随机数生成,最后介绍了随机数在密码学中的使用场景。

    展开全文
  • 使用Random产生随机数 使用步骤: 导入包 import java.util.Random; 创建对象 Random r = new Random(); 产生随机数 int num = r.nextInt(10); 解释: 10代表的是一个范围,如果括号写10,产生的随机数就是0-9...

    使用Random产生随机数

    使用步骤:

    1. 导入包

      import java.util.Random;

    2. 创建对象

      Random r = new Random();

    3. 产生随机数

      int num = r.nextInt(10);

      解释: 10代表的是一个范围,如果括号写10,产生的随机数就是0-9,括号写20,参数的随机数则是0-19

    示例代码:

    import java.util.Random;  //导包
    public class RandomDemo {
    	public static void main(String[] args) {
    		//创建对象
    		Random r = new Random();
    		//用循环获取10个随机数
    		for(int i=0; i<10; i++) {
    			//获取随机数
    			int number = r.nextInt(10);
    			System.out.println("number:" + number);
    		}
    		//需求:获取一个1-100之间的随机数
    		int x = r.nextInt(100) + 1;  //由于括号中100只能表示0-99的范围,所以在获取随机数以后,在获取的随机数的基础上+1,便能实现随机数的范围在1-100之间。
    		System.out.println(x);
    	}
    }
    

    随机数范围确定公式:

    int x = r.nextInt(上限-下限+1)+下限
    解释:由于java中的Random类中的nextInt(a)方法生成的随机数一定是0至 a-1,而我们想要的范围比如是50-80;因此需要在Random类中的nextInt(a)方法生成的随机数的基础上+50,这样既可保证我们得到的随机数最小一定是50;由于加了50,所以还应该保证Random类中的nextInt(a)方法生成的随机数加50之后不能超过80;所以可以确定下来 a = 上限-下限+1。

    例如有如下需求:
    生成 50 至 80之间的随机数;(50和80是包含的)
    代码如下:

    import java.util.Random;  //1:导包
    public class RandomDemo{
    	public static void main(String[] args){
    		//2:创建对象
    		Random r = new Random();
    		//3:套用公式,得到我们想要的随机数;
    		int x = r.nextInt(80-50+1)+50;   //为了方便记忆与理解,括号内可直接套用公式,不用计算结果,效率更快。
    		System.out.println(x);
    	}
    }
    
    展开全文
  • Java-Random产生随机数

    2020-07-28 15:46:37
    1、用nextInt()方法生成一个int类型的随机数 public class Person { public static void main(String[] args) { Random random = new Random(); int num = random.nextInt(); System.out.println(num); } } 2...

    1、用nextInt()方法生成一个int类型的随机数

    public class Person {
        public static void main(String[] args) {
            Random random = new Random();
            int num = random.nextInt();
            System.out.println(num);
        }
    }
    

    2、用nextInt(int n)方法生成一个[0,n)范围内的随机数

    public class Person {
        public static void main(String[] args) {
            Random random = new Random();
            //生成一个[0,3)范围内的随机数,包括0不包括3
            int num = random.nextInt(3);
            System.out.println(num);
        }
    }
    

    3、用nextInt(int n)方法生成一个[m,n]范围内的随机数
    int num = random.nextInt(x)+y;
    num的范围在[m,n]范围内则:
    x = n+1-m;
    y = m;

    public class Person {
        public static void main(String[] args) {
            Random random = new Random();
            for(int i = 0; i < 100; i++) {
                //生成[3,9]范围内的随机数
                int num = random.nextInt(7) + 3;
                System.out.println(num);
            }
        }
    }
    
    展开全文
  • java random生成随机数详解

    千次阅读 2020-11-25 17:11:40
    可以使用System.currentTimeMillis(),但这这种方式获取的不能称为严格意义的随机数,虽然他是一直变的,但他不是随机的。表示获取当前系统时间,产生一个当前的毫秒,这个毫秒其实就是自1970年1月1日0时起的毫秒数 ...

    想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
    在这里插入图片描述


    1,使用System.currentTimeMillis()

    可以使用System.currentTimeMillis(),但这这种方式获取的不能称为严格意义的随机数,虽然他是一直变的,但他不是随机的。表示获取当前系统时间,产生一个当前的毫秒,这个毫秒其实就是自1970年1月1日0时起的毫秒数

        public static void main(String[] args) {
            System.out.println("currentTimeMillis函数执行的结果:" + System.currentTimeMillis());
        }
    

    看下执行结果

    > Task :javatest:BRandom.main()
    currentTimeMillis函数执行的结果:1606293741253
    

    2,使用Math.random()

    这个方法会生成一个大于等于0,并且小于1的随机数(不等于1,但可以等于0),返回的是double类型的。

    Math.random()*(n-m)+m:表示的是生成大于等于m且小于n的随机数(这里m<n);

        public static void main(String[] args) {
            System.out.println("Math.random()函数执行的结果:" + Math.random());
        }
    

    3,使用Random类

    直接初始化Random来生成随机数

        public static void main(String[] args) {
            Random random = new Random();//创建随机数生成器
            System.out.println(random.nextDouble());//获取的随机数范围是[0.0,1.0)
            System.out.println(random.nextFloat());//获取的随机数范围是[0.0,1.0)
            System.out.println(random.nextBoolean());//获取随机的boolean类型
            System.out.println(random.nextInt());//获取随机的int类型数据
            System.out.println(random.nextInt(10));//获取的随机数范围是[0,10)
            System.out.println(random.nextLong());//获取随机的long类型数据
        }
    

    上面的方式生成的随机数每次都是随机的,只要每次运行,结果都会不一样。

    这里还可以使用种子seed来创建随机数,像下面代码这样,虽然运行的结果也是随机数,但每次运行的时候结果都是一样的。

        public static void main(String[] args) {
            Random random = new Random(10);//创建随机数生成器
            System.out.println(random.nextDouble());//获取的随机数范围是[0.0,1.0)
            System.out.println(random.nextFloat());//获取的随机数范围是[0.0,1.0)
            System.out.println(random.nextBoolean());//获取随机的boolean类型
            System.out.println(random.nextInt());//获取随机的int类型数据
            System.out.println(random.nextInt(10));//获取的随机数范围是[0,10)
            System.out.println(random.nextLong());//获取随机的long类型数据
        }
    

    比如我现在电脑运行的结果如下

    > Task :javatest:BRandom.main()
    0.7304302967434272
    0.25780278
    false
    254270492
    6
    4503168388465453601
    

    无论运行多少次,结果都是不会变的。


    在这里插入图片描述

    展开全文
  • Java Random-随机数

    2020-06-25 21:15:39
    第一种: 使用java.util.Random类实现 这里所要说明的是以下面的代码为例: 这行代码将生成范围0~100 之间的随机数,有趣的是,取值可能为 0 ,但不可能为 100。我们用中学数学课学习的区间表示法,表示为:[0, ...
  • java random生成随机数

    2019-09-15 16:06:45
    生成指定范围内的随机数 这个是最常用的技术之一。程序员希望通过随机数的方式来处理众多的业务逻辑,测试过程中也希望通过随机数的...以 Java 语言为例,我们观察其 Random 对象的 nextInt(int) 方法,发现这个方法...
  • int a=random.nextInt(10) //定义一个变量用来接收随机数生成器产生随机数,这个随机数因为设置了随机变量,所以每次产生的结果是一样的,这个每次的意思是每一次运行,如果用一个含有多个位的数组来接受这个...
  • Random产生随机数

    2019-10-07 21:11:33
    import java.util.Random;...//Random产生随机数 public class RandomTest01 { public static void main(String[] args) { //产生[1,5]的随机数 int n = 5; Random r = new Random(); for...
  • 通过使用java.uitl.Random产生一个1-10内的随机数。例: 1 Random random = new Random(); 2 int i = Math.abs(random.nextInt() % 10) + 1; 3 System.out.println("随机数: " + i); Random使用了System....
  • Java Random 随机数

    千次阅读 2016-07-31 22:39:39
    Java Random 随机数实际开发中产生随机数的使用很常见,因此在程序中产生随机数的操作很重要。在Java中主要提供了两种方法产生随机数,分别是调用Math类的random()方法和Random类提供的产生各种数据类型的随机数的...
  • Java产生随机数

    2017-03-09 10:59:07
     通过这个方法可以让系统产生随机数。不过默认情况下,其产生的随机数范围比较小,为大于等于0到小于1的 double型随机数。虽然其随机数产生的范围比较小,不能够满足日常的需求。如日常工作中可能需要产生整数的...
  • Java Random随机数

    2018-11-27 19:03:11
    //产生一个[0,1)之间的随机数。 Math.random(): //返回指定范围的随机数(m-n之间)的公式: Math.random()*(n-m)+m; //或者 Math.random()*(n+1-m)+m 2.java.util.Random Random():创建一个新的随机数生...
  • Java产生随机数的两个方法  在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述在Java产生随机数的两个方法,更多Java...
  • Random.nextInt() 随机产生 [0,n) 的int值 用new创建 Refer
  • Random产生随机数模拟投掷硬币

    千次阅读 2018-03-28 10:55:23
    上概率论那会,“猪”老师曾在课上这么表示过:你透支一枚硬币,投掷的次数越多,...总的来说就是产生01两个随机数并统计他们出现的次数没啥特别的思路,就直接贴代码了!package cn.edu.nuist.march; import jav...
  • Java语言中,除了可以通过random 方法来产生随机数之外,还可以通过一个random类来产生随机数。程序开发人员可以通过实例化一个Random对象来创建一个随机数的生成器。如Random i=new Random()。通过这条语句就利用...
  • java产生随机数

    2016-04-28 16:23:00
    第一种: 利用Math.random()方法,它可以产生一个在[0.0,1.0]区间内的一个双精度浮点数。...利用Random类中的nextXXX()方法来产生随机数 Random random = new Random(); random.nextInt(n);//产生0~n-1...
  • Math.random()默认产生大于等于0.0且小于1.0之间的随机double型随机数(返回[0,1)随机数)。 如果我们要随机产生一个int型的两位数[10,99]。 (int)(Math.random()*90+10) 因为要产生10-99 所以x90 得到的是 [0,90)再...
  • Java当中产生随机数

    2016-04-23 16:45:27
    Java当中产生随机数可以直接使用Math.random(), int num=(int)(Maht.random()*100) 100只是表示将产生的随机小数的值扩大了100倍,可以根据实际情况,乘以任意倍数 也可以new一个Randow for example:  Random...
  • import java.util.Random; public class RandomDemo { public static void main(String[] args) { //创建对象 Random r = new Random(); //用循环获取10个随机数 for(int i=0; i<10; i++) { //获取...
  • Java产生随机数的两个方法 一、利用random方法来生成随机数。  在Java语言中生成随机数相对来说比较简单,因为有一个现成的方法可以使用。在Math类中,Java语言提供了一个叫做random的方法。通过这个方法可以...
  • Java产生随机数的方法小结

    千次阅读 2019-10-07 13:01:23
    Java 中提供了很多的方法能够产生随机数。我们今天介绍其中最为简单的两种,对于初学者来说较为友好,同时附了两个简单的案例供大家参考。
  • Java类库中提供的产生随机数的方法总结
  • javaRandom随机数使用

    千次阅读 2020-04-26 17:08:15
    import java.util.Random; 2.创建对象 Random r = new Random(); 3.获取随机数 int number = r.nextInt(10); //获取数据的范围:[0,10)包括0,不包括10 例子:获取1到100之间的随机数 //获取1到100之间的随机数 ...
  • 在一个for循环中连续使用 Math.random()产生多个随机数,其产生随机数是相同的,如何修改使产生的多个随机数是不同的?????

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,552
精华内容 15,020
关键字:

javarandom产生随机数

java 订阅