zoukankan      html  css  js  c++  java
  • java中Random实现原理

    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类原理剖析

  • 相关阅读:
    LR十九:Analysis 图标分析
    Llinux:mysql的安装教程
    Jmeter28:linux下实现压测-html报表生成-控制台参数优化
    Llinux:自动分配ip的方法
    Llinux:环境变量的配置-java-JMETER
    if _ else if _ else,case,程序逻辑判断- java基础
    LR十八:Controller组件- 集合点的功能-loadrunner
    LR十七:Controller
    Jmeter27:TCP_协议_socket接口
    LR十六:socket_tcp协议_loadrunner测试
  • 原文地址:https://www.cnblogs.com/strongmore/p/14978811.html
Copyright © 2011-2022 走看看