【小家java】Java中Random ThreadLocalRandom 设置随机种子获取随机数精讲(上)

简介: 【小家java】Java中Random ThreadLocalRandom 设置随机种子获取随机数精讲(上)


相关阅读

【小家java】java5新特性(简述十大新特性) 重要一跃

【小家java】java6新特性(简述十大新特性) 鸡肋升级

【小家java】java7新特性(简述八大新特性) 不温不火

【小家java】java8新特性(简述十大新特性) 饱受赞誉

【小家java】java9新特性(简述十大新特性) 褒贬不一

【小家java】java10新特性(简述十大新特性) 小步迭代

【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本


每篇一句

世界上唯一可以不劳而获的,就是贫穷。唯一可以无中生有的,就是梦想。虽然世界很残酷,但是只要你愿意走,总会有路


我们都知道,随机数在太多的地方使用了,比如加密、混淆数据等,我们使用随机数是期望获得一个唯一的、不可仿造的数字,以避免产生相同的业务数据造成混乱。

在Java项目中通常是通过Math.random方法和Random类来获得随机数的。那么本文针对于这两种产生随机数的方法进行源码级别的精度,让你以后不再犯错。


先说平时使用

绝大多数情况,我们其实是想通过此类来生成一个随机整数。此处不鳌诉推倒过程,直接公布一个公式:

Random rand = new Random();
int num = rand.nextInt(MAX - MIN + 1) + MIN;


因此,我们需要[min,max]之间的随机数,直接这么来使用就ok了 闭区间哦


java产生随机数的几种方式


1.使用Math.random()方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以一定的数,比如说乘以100,他就是个100以内的随机


2.使用java.util这个包里面提供了一个Random的类(最常用)


3.使用currentTimeMillis的取模算法(使用较少)


java中通过这几种方法产生的随机数叫伪随机数,并不是真正的随机数。这里简单科普一下伪随机和真随机的区别:


伪随机(preundorandom):通过算法产生的随机数都是伪随机!!

真随机:比如,通过机器的硬件噪声产生随机数、通过大气噪声产生随机数。(只有通过真实的随机事件产生的随机数才是真随机)


一、java.lang.Math.Random;

调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。


 public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            int num = (int) (Math.random() * 10);
            System.out.println("num is:" + num);
        }
    }
输出:
num is:1
num is:4
num is:3
第二次输出:
num is:0
num is:6
num is:5


我们会发现,每次输出的值都是不一样的,但是都保持在[0,10)的区间里面

在使用Math.Random()的时候需要注意的地方时该函数是返回double类型的值,所以在要赋值给其他类型的变量的时候注意需要进行类型转换


二、java.util.Random;


1、java.util.Random类中实现的随机算法是伪随机,也就是有规则的随机,所谓有规则的就是在给定种(seed)的区间内随机生成数字(后面会有例子验证这一点);


2、相同种子的Random对象,相同次数生成的随机数字是完全相同的(所以才叫伪随机嘛);


3、Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率均等;


它提供了两种构造函数:


一、Random( ):无参构造方法(不设置种子)

虽然表面上看我们未设置种子,但Random构造方法里有一套自己的种子生成机制。参照内部源码如下


public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }
    private static long seedUniquifier() {
        // L'Ecuyer, "Tables of Linear Congruential Generators of
        // Different Sizes and Good Lattice Structure", 1999
        for (;;) {
            long current = seedUniquifier.get();
            long next = current * 181783497276652981L;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
        }
    }
    private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);

这个其实就是取当前毫秒值,然后通过“线性同余算法”来生成的一个数字。下面摘抄了生成种子的过程,仅供参考:


1、获得一个长整形数作为“初始种子”(系统默认的是8682522807148012L)

2、不断与一个变态的数——181783497276652981L相乘(天知道这些数是不是工程师随便滚键盘滚出来的-.-)得到一个不能预测的值,直到 能把这个不能事先预期的值 赋给Random对象的静态常量seedUniquifier 。因为多线程环境下赋值操作可能失败,就for(;;)来保证一定要赋值成功

3、与系统随机出来的nanotime值作异或运算,得到最终的种子


因为取了机器当前的纳秒值nanoTime,所以不管运行多少次,出现的值都是不一样的。但是由于这随机数是通过算法计算出来的,所以其实是有规律性的,如果精通这个算法,是可以推测出下一个值是什么,所以我们才叫这种叫伪随机数。


相关文章
|
3月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
95 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
3月前
|
Java Linux iOS开发
如何设置 Java 的环境变量
设置Java环境变量是使用Java开发工具和运行Java程序的前提。主要步骤包括:安装JDK,配置系统环境变量中的JAVA_HOME、PATH和CLASSPATH,确保命令行可直接调用javac和java命令。
78 6
|
3月前
|
安全 Java Linux
java程序设置开机自启
java程序设置开机自启
173 1
|
3月前
|
Java
java的Random类和Arrays.sort类使用实例
java的Random类和Arrays.sort类使用实例
15 0
|
3月前
|
Java
java值random类的使用
java值random类的使用
16 0
|
3月前
|
Java
java的Math类和random类
java的Math类和random类
20 0
|
5月前
|
JSON Java API
【Azure API 管理】通过Java APIM SDK创建一个新的API,如何为Reqeust的Representation设置一个内容示例(Sample)?
【Azure API 管理】通过Java APIM SDK创建一个新的API,如何为Reqeust的Representation设置一个内容示例(Sample)?
|
10天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
12天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
12天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。