java生成隨機數的三種方式


1、java.util.Random()

  偽隨機,如果不傳入種子,以當前系統時間為種子,通過一系列計算得出隨機值,種子相同的情況下,每次調用得到的隨機值是固定的

2、Math.random()  

    public static double random() {
        return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
    }
    private static final class RandomNumberGeneratorHolder {
        static final Random randomNumberGenerator = new Random();
    }

  Math內部也是通過java.util.Random()實現的

3、java.security.SecureRandom()

  new SecureRandom();
  SecureRandom.getInstance("");
  SecureRandom.getInstanceStrong();

  可以使用以上三種方式生成對象,推薦使用new SecureRandom(),使用系統默認的算法並由系統生成種子

  SecureRandom繼承於Random類,其具體的實現類為SecureRandomSpi,與平台相關,以JDK版本jdk-8u251-linux-x64為例,在Linux系統下,其默認的實現類為NativePRNG,隨機源為/dev/random以及/dev/urandom

  /dev/random和/dev/urandom是Linux系統中提供的隨機偽設備,使用這兩個設備可以為應用提供不為空的隨機字節流,兩者的區別是/dev/random在系統噪聲不足時,會產生阻塞,而/dev/urandom是/dev/random的一個副本,它會重復使用熵池中的數據以產生偽隨機數據,因此不會有阻塞的問題

  NativePRNG基於混合模式,為生成隨機數與隨機種子提供了不同的支持

                case MIXED:
                    File var4 = null;
                    URL var3;
                    if ((var3 = NativePRNG.getEgdUrl()) != null) {
                        try {
                            var4 = SunEntries.getDeviceFile(var3);
                        } catch (IOException var7) {
                            ;
                        }
                    }

                    if (var4 != null && var4.canRead()) {
                        var1 = var4;
                    } else {
                        var1 = new File("/dev/random");
                    }

                    var2 = new File("/dev/urandom");
                    break;

  對於隨機數的生成,NativePRNG總是使用/dev/urandom作為隨機源,而對於種子的生成,其隨機源則取決於配置。在NativePRNG.getEgdUrl()方法中,程序會讀取配置java.security.egd以及securerandom.source配置

  比如配置-Djava.security.egd=file:/dev/urandom,則采用非阻塞模式,而如果配置-Djava.security.egd=file:/dev/urandom,則采用阻塞模式,系統默認也是采用阻塞模式生成種子,以保證足夠的隨機性

    private static final String seedSource = (String)AccessController.doPrivileged(new PrivilegedAction<String>() {
        public String run() {
            String var1 = System.getProperty("java.security.egd", "");
            if (var1.length() != 0) {
                return var1;
            } else {
                var1 = Security.getProperty("securerandom.source");
                return var1 == null ? "" : var1;
            }
        }
    });

  需要注意的是,SecureRandom.getInstanceStrong()方法,並不遵從上述方式,而是讀取配置securerandom.strongAlgorithms,並以此構建隨機生成器,在Linux系統下,該配置默認為NativePRNGBlocking:SUN,即采用NativePRNG.Blocking類作為其實現,該方法與SecureRandom.getInstance("NativePRNGBlocking","SUN")語義相同

                case BLOCKING:
                    var1 = new File("/dev/random");
                    var2 = new File("/dev/random");
                    break;

  由代碼可知,getInstanceStrong()返回的隨機生成器,對於生成隨機種子以及隨機數都是訪問/dev/random,這個方法性能上是非常差的,沒有特殊需求,不推薦使用

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM