Math.random() 方法
调用方法
public static void main(String[] args) {
System.out.println(Math.random()); //0-1 的随机数
}
源码如下:
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
randomNumberGenerator 的生成源码
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
所以从源码上看,Math.random() = Random.nextDouble(),这是线程安全的,因为底层实现CAS(Compare and Swap)生成随机数,Java 并发机制实现原子操作有两种:一种是锁,一种是 CAS。
Random()方法
调用方法
public static void main(String[] args) {
Random random1=new Random(2);
random1.nextInt(100);
}
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)) // CAS(Compare and Swap)生成随机数
return next;
}
}
有参的构造方法
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()空参时,构造方法里使用当前系统时间相关的一个数字作为种子数,该种子数只作为随机算法的起源数字,与生成的随机数区间无关系。这个是线程安全的,因为底层实现CAS(Compare and Swap)生成随机数。
2.如果 Random 的随机种子一样的话,每次生成的随机数都是可预测的(都是一样的)。 代码如下
Random random1=new Random(2);
Random random2=new Random(2);
for(int index=0;index<10;index++)
{
System.out.println("random1--"+random1.nextInt(100));
System.out.println("random2--"+random2.nextInt(100));
}
System.out.println(Math.random());
输出如下
random1--8
random2--8
random1--72
random2--72
random1--40
random2--40
random1--67
random2--67
random1--89
random2--89
random1--50
random2--50
random1--6
random2--6
random1--19
random2--19
random1--47
random2--47
random1--68
random2--68
ThreadLocalRandom的方法
Random 在生成随机数时使用的是CAS 来解决线程安全问题的,如果多个线程操作时,效率是比较低的。可以使用 ThreadLocalRandom 来解决 Random 执行效率比较低的问题。
调用方法
public static void main(String[] args) {
// 得到 ThreadLocalRandom 对象
ThreadLocalRandom random = ThreadLocalRandom.current();
for (int i = 0; i < 10; i++) {
// 生成 0-9 随机整数
int number = random.nextInt(10);
// 打印结果
System.out.println("生成随机数:" + number);
}
}
源码如下:
public int nextInt(int bound) {
// 参数效验
if (bound <= 0)
throw new IllegalArgumentException(BadBound);
// 根据当前线程中种子计算新种子
int r = mix32(nextSeed());
int m = bound - 1;
// 根据新种子和 bound 计算随机数
if ((bound & m) == 0) // power of two
r &= m;
else { // reject over-represented candidates
for (int u = r >>> 1;
u + m - (r = u % bound) < 0;
u = mix32(nextSeed()) >>> 1)
;
}
return r;
}
final long nextSeed() {
Thread t; long r; // read and update per-thread seed
// 获取当前线程中 threadLocalRandomSeed 变量,然后在种子的基础上累加 GAMMA 值作为新种子
// 再使用 UNSAFE.putLong 将新种子存放到当前线程的 threadLocalRandomSeed 变量中
UNSAFE.putLong(t = Thread.currentThread(), SEED,
r = UNSAFE.getLong(t, SEED) + GAMMA);
return r;
}