Java Random类源码分析
来源:互联网 发布:2016年进出口数据分析 编辑:程序博客网 时间:2024/05/19 13:28
前言
每次特别好奇计算机如何产生随机数的,他这种完全按照规律执行的代码,如何才能产生随机数呢?这里我给出大家一个解答——答案是不可以。计算机产生的伪随机数。即给出一个种子,给出一些复杂的算法。把他变大之后,就产生了类似随机数的序列。
正文
下面我们来看一下代码
Random random = new Random(50); System.out.println(random.nextInt(100)); System.out.println(random.nextInt(100)); Random random1 = new Random(50); System.out.println(random1.nextInt(100)); System.out.println(random1.nextInt(100));
运行结果是:
17
88
17
88
看呆了吧,这玩意完全就类似一个数组,如果你不信,你可以多输出几次,下面我们来看下源码。分析下到底他是一个什么样子的数组。并且如何才能产生我们需要的“伪随机数”。
首先观察构造函数,其实就时找到一个seed,也许你会看到比较复杂的东西,我们先看比较简单的有参构造函数
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); } }
这里本来我不想贴代码的。可是我发现无参构造函数比较复杂。我就还是研究下吧,注释很容易明白,一切的一切都是为了继承。其实我们只走if(true)流程。我们看下initialScramble(seed)
private static final long mask = (1L << 48) - 1; private static final long multiplier = 0x5DEECE66DL; private static long initialScramble(long seed) { return (seed ^ multiplier) & mask; }
这里估计大部分人会迷茫,这他妹的是什么。说实在的我也不懂。multiplier
这个数据为啥是这个。有撒用,貌似一个最合理的解释的是吧数字变大,可以让种子变得更加貌似随机一点。至于mask,貌似要去掉正负标志位,其实没啥用,继续来研究另外一个构造函数。
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; } }
seedUniquifier()
这个函数我不懂,网上搜到说是多线程。大家不要介意。只要知道这个数字貌似比较大,并且跟当前时间xor后更显得随机,好了开始我们真正的随机数的产生。
public boolean nextBoolean() { return next(1) != 0; }
这个最简单。我们会发现出现一个next函数,看下next函数。
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)); }
这里最关键的是第六行,这是一个算法,如果非要了解为啥的只能去找《计算机设计艺术》第二卷。这里反正就是
nextseed = a* oldseed + b ;
这个东西。我们在getBool
中传递参数是1.我们很容易发现我们只保留了一位二进制数字。当然只能取两种结果。
好了我们来看一个复杂的东东
public int nextInt(int bound) { if (bound <= 0) throw new IllegalArgumentException(BadBound); int r = next(31); int m = bound - 1; if ((bound & m) == 0) // i.e., bound is a power of 2 r = (int)((bound * (long)r) >> 31); else { for (int u = r; u - (r = u % bound) + m < 0; u = next(31)) ; } return r; }
第四行r为一个无符号的int型’随机数’。if内部解释很清楚,直接看else。整理后的代码是这样,其实就是一直取余数,最终得带的余数小鱼边界就好了。不在详细研究。
至于小数的形式。这里不在研究,也比较简单。
下面说下如果想产生我们认为的足够随机的随机数。其实很简单。聪明的我们发现调用无参构造函数就好了嘛!的确,这里我就不再给大家写代码。另外还有一个java.math.random()
类对这个类进行了封装我们可以调用Math.random()
.关于线程我这里给不出一个合理的答案。至于我这个写Android的应用的一般不会出现这种问题。这里就不再深入研究了。以后有机会再补充。
后记
总算理解了大概这个玩意。这里总算明白这个问题了,总算不是完全不直到到底随机数如何产生的。希望对大家有帮助
- Java Random类源码分析
- Java Random类深入分析
- 分析JAVA的Random类
- 分析JAVA的Random类(1)
- java.util.Random 分析
- [HGE]-源码分析-9 input,power,random
- LevelDB源码分析之七:Random
- Java中的Random类
- java Random类
- JAVA的Random类
- JAVA的Random类
- java Random 类
- JAVA的Random类
- java Random类详解
- java Random类详解
- JAVA的Random类
- java Random类详解
- Java中的Random类
- apache服务器的相关tips
- 4. 流程控制语句
- “正被停用的激活上下文不是最近激活的”的错误的解决
- 支付宝在线支付
- js如何实现拆分字符串并依次输出
- Java Random类源码分析
- 【洛谷2022】 神奇数学题
- 朱刘算法
- R语言入门-R语言环境安装与Rstudio安装
- 基于Zookeeper的服务注册与发现
- C语言单链表
- 5. 数据结构
- webrtc:音频处理流程
- opengl DDA直线算法的实现