java隨機數的陷阱

前言

隨機數咱們應該不陌生,業務中咱們用它來生成驗證碼,或者對重複性要求不高的id,甚至咱們還用它在年會上搞抽獎。今天咱們來探討一下這個東西。若是使用不當會引起一系列問題。java

java中的隨機數

咱們須要在Java中隨機生成一個數字。java開發中咱們一般使用java.util.Random來搞,它提供了一種僞隨機的生成機制。Jvm 經過傳入的種子(seed)來肯定生成隨機數的區間,只要種子同樣,獲取的隨機數的序列就是一致的。並且生成的結果都是能夠預測的。是一種僞隨機數的實現,而不是真正的隨機數。來肯定使用的可是有些用例直接使用可能會致使一些意想不到的問題。Random的一個廣泛用法:算法

// Random 實例
Random random = new Random();
//調用 nextInt() 方法 此外還有nextDouble(), nextBoolean(), nextFloat(), ...
random.nextInt();複製代碼

或者,咱們可使用java中的數學計算類:安全

Math.random();複製代碼

Math類只包含一個Random實例來生成隨機數:多線程

public static double random() {
    Random rnd = randomNumberGenerator;
    if (rnd == null) {
      // 返回一個新的Random實例
    rnd = initRNG();
   }
    return rnd.nextDouble();
    }複製代碼

java.util.Random的用法是線程安全的。可是,在不一樣線程上併發使用相同的Random實例可能會致使爭用,從而致使性能不佳。其緣由是使用所謂的種子來生成隨機數。種子是一個簡單的數字,它爲生成新的隨機數提供了基礎。咱們來看看Random中的next(int bits)方法:併發

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));}複製代碼

首先,舊種子和新種子存儲在兩個輔助變量上。在這一點上,創造新種子的原則並不重要。要保存新種子,使用compareAndSet()方法將舊種子替換爲下一個新種子,但這僅僅在舊種子對應於當前設置的種子的條件下才會觸發。若是此時的值由併發線程操縱,則該方法返回false,這意味着舊值與例外值不匹配。由於是循環內進行的操做,那麼會發生自旋,直到變量與例外值匹配。這可能會致使性能不佳和線程競爭。dom

多線程下的隨機數

若是更多線程主動生成具備相同Random的實例的新隨機數,則上述狀況發生的機率越高。對於生成許多(很是多)隨機數的程序,不建議使用這種方式。在這種狀況下,您應該使用ThreadLocalRandom,它在1.7版本中添加到Java中。ThreadLocalRandom擴展了Random並添加選項以限制其使用到相應的線程實例。爲此,ThreadLocalRandom的實例保存在相應線程的內部映射中,並經過調用current()來返回對應的Random。使用方式以下:性能

ThreadLocalRandom.current().nextInt()複製代碼

安全的隨機數

經過對Random的一些分析咱們能夠知道Random事實上是僞隨機,是能夠推導出規律的,並且依賴種子(seed)。若是咱們搞抽獎或者其餘一些對隨機數敏感的場景時,用Random就不合適了,容易被人鑽空子。JDK提供了SecureRandom來解決這個事情。SecureRandom是強隨機數生成器,它能夠產生高強度的隨機數,產生高強度的隨機數依賴兩個重要的因素:種子和算法。算法是能夠有不少的,一般如何選擇種子是很是關鍵的因素。 Random的種子是System.currentTimeMillis(),因此它的隨機數都是可預測的, 是弱僞隨機數。強僞隨機數的生成思路:收集計算機的各類信息,鍵盤輸入時間,內存使用狀態,硬盤空閒空間,IO延時,進程數量,線程數量等信息,CPU時鐘,來獲得一個近似隨機的種子,主要是達到不可預測性。說的更通俗就是,使用加密算法生成很長的一個隨機種子,讓你沒法猜想出種子,也就沒法推導出隨機序列數。this

總結

今天咱們探討了業務中常常使用的隨機數的一些機制和一些場景下的一些陷阱,但願你在使用隨機數的時候能避免這種陷阱。加密

關注公衆號:碼農小胖哥,獲取更多資訊spa

相關文章
相關標籤/搜索