java中Random实现原理

您所在的位置:网站首页 random函数的原理 java中Random实现原理

java中Random实现原理

#java中Random实现原理| 来源: 网络整理| 查看: 265

Random使用

java中使用Random类来产生随机数。

import java.util.Random; public class Client { public static void main(String[] args) { test(); test(); } private static void test() { Random random = new Random(10000); for (int i = 0; i < 5; i++) { System.out.print(random.nextInt(10000) + " "); } System.out.println(); } }

输出结果为

2208 572 9116 3475 4500 2208 572 9116 3475 4500

只要种子相同,产生的随机数序列就是相同的,所以说Random是一种伪随机数的实现。

Random原理 /** * 随机数种子 */ private final AtomicLong seed; /** * 无参构造器,使用当前时间纳秒值 */ 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 * 1181783497276652981L; if (seedUniquifier.compareAndSet(current, next)) return 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)); }

通过一个固定算法,使用CAS将一个旧的种子更新为新种子。

ThreadLocalRandom

Random获取随机数使用CAS更新种子,在高并发环境下会大量自旋重试,性能下降,这种情况下可以使用ThreadLocalRandom。

import java.util.concurrent.ThreadLocalRandom; public class Client2 { public static void main(String[] args) { ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current(); for (int i = 0; i < 5; i++) { System.out.print(threadLocalRandom.nextInt(100) + " "); } } }

输出为

73 78 0 68 12

通过一个静态方法创建,不能自己设置种子。

public class ThreadLocalRandom extends Random { // 可以直接操作内存的工具类 private static final Unsafe U = Unsafe.getUnsafe(); // 种子 private static final long SEED = U.objectFieldOffset (Thread.class, "threadLocalRandomSeed"); private static final long PROBE = U.objectFieldOffset (Thread.class, "threadLocalRandomProbe"); /** 单例 */ static final ThreadLocalRandom instance = new ThreadLocalRandom(); /** * 获取单例对象 */ public static ThreadLocalRandom current() { if (U.getInt(Thread.currentThread(), PROBE) == 0) localInit(); return instance; } }

使用饿汉式的单例模式来创建ThreadLocalRandom对象

/** * Returns a pseudorandom {@code int} value. * * @return a pseudorandom {@code int} value */ public int nextInt() { return mix32(nextSeed()); } final long nextSeed() { Thread t; long r; // read and update per-thread seed U.putLong(t = Thread.currentThread(), SEED, r = U.getLong(t, SEED) + GAMMA); return r; }

ThreadLocalRandom每个线程保存一份种子,每次更新自己线程的种子,避免高并发下的竞争。

/** The current seed for a ThreadLocalRandom */ @jdk.internal.vm.annotation.Contended("tlr") long threadLocalRandomSeed; /** Probe hash value; nonzero if threadLocalRandomSeed initialized */ @jdk.internal.vm.annotation.Contended("tlr") int threadLocalRandomProbe;

种子保存在Thread类下threadLocalRandomSeed和threadLocalRandomProbe字段,原理类似于ThreadLocal,用空间换时间。

SecureRandom import java.security.SecureRandom; public class Client3 { public static void main(String[] args) { SecureRandom secureRandom = new SecureRandom(); System.out.println(secureRandom.getAlgorithm()); for (int i = 0; i < 5; i++) { System.out.print(secureRandom.nextInt(100) + " "); } } }

输出为

DRBG 7 23 20 92 31

SecureRandom是一个强随机数生成器,会收集计算机的各种信息,使用加密算法创建随机数。windows下默认使用DRBG算法。

参考

java.util.Random 实现原理 第3章 Java并发包中ThreadLocalRandom类原理剖析



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3