筆者最近在練習Mysql語句優化,奈何年少不懂,找不到百萬級別的測試數據,只好用java隨機生成數據湊合用一下,因此寫下此篇博客,經測試生成500萬條數據後臺用了9秒,徹底能夠接受java
random僞隨機數類在 java.util 包下,是最經常使用的隨機數生成器,其使用線性同餘公式來生成隨機數,因此才說是僞隨機。該類的實例是線程安全的,多線程併發使用可能會遇到爭用問題,這時可用 ThreadLocalRandom 來解決這個問題,此外還有 SecureRandom 、SplittableRandom 隨機生成器,這裏就不擴展說明了sql
類型 | 名字 | 解釋 |
---|---|---|
Random() | 默認構造函數 | |
Random(long seed) | 有參構造,用種子建立僞隨機生成器 | |
int | nextInt | 返回生成器中生成表序列中的下一個僞隨機數 |
int | nextInt(int n) | 返回均勻分佈於區間 [0,n)的僞隨機數 |
double | nextDouble | 返回下一個僞隨機數 [0.0,1.0) |
先看無參構造,直接上源碼安全
// 無參構造也是調用有參構造的,那麼放出有參構造,再看裏面具體內容 public Random() { this(seedUniquifier() ^ System.nanoTime()); } // 有參構造接收長整型種子參數 public Random(long seed) { // 判斷是否本類 if (getClass() == Random.class) // 能夠看出長整型種子是Atomic原子型的,即線程安全 // initialScramble() 是seed與兩個具體數值運算,這裏不給出了 this.seed = new AtomicLong(initialScramble(seed)); else { // subclass might have overriden setSeed // 翻譯:子類可能重寫setSeed方法 this.seed = new AtomicLong(); setSeed(seed); } } // 再回無參構造內部 // 其中 ^ System.nanoTime() 表示與系統納秒異或運算,也就是說隨機數依賴於時間 this(seedUniquifier() ^ System.nanoTime()); private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L); 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; // 用到了CAS輕量鎖 if (seedUniquifier.compareAndSet(current, next)) return next; } }
再看nextInt方法,有參的方法用邏輯運算把範圍指定,這裏就不介紹了多線程
public int nextInt() { return next(32); } 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)); // 可能這些位運算就是線性同餘把 }
簡單使用併發
Random r1 = new Random(); Random r2 = new Random(); Random r3 = new Random(); Random r4 = new Random(1000); Random r5 = new Random(1000); System.out.println(r1.nextInt()); System.out.println(r2.nextInt()); System.out.println(r3.nextInt(100)); System.out.println(r4.nextInt()); System.out.println(r5.nextInt());
491030142 2021835847 49 -1244746321 -1244746321
從結果和源碼能夠看出:app
new Random.nextInt(int n)
來生成僞隨機數
咱們最經常使用仍是這個函數,靜態調用方便簡單dom
// 底層仍是用了Random類 public static double random() { return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble(); } // 新建一個依賴時間的隨機數生成器 private static final class RandomNumberGeneratorHolder { static final Random randomNumberGenerator = new Random(); } // 位運算增強隨機 public double nextDouble() { return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT; }
從源碼能夠看出:ide
生成給定範圍的僞隨機數函數
// 給定範圍 int min = 10; int max = 15; // 生成僞隨機小數 double num = Math.random(); // 範圍邏輯運算,想一下很簡單的 int rs = (int)(num * (max - min + 1) + min); System.out.println(rs); // 須要整數的位數
// 密碼字符範圍 String range = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+[];',.<>?:{}|"; // 生成100個僞隨機密碼 for(int i = 0; i < 100; i++){ // 字符串 StringBuffer bf = new StringBuffer(); // 密碼長度8~20 int len = (int)(Math.random() * (20 - 8 + 1) + 8); for(int j = 0; j < len; j++){ int index = new Random().nextInt(range.length()); bf.append(range.charAt(index)); } System.out.println(bf.toString()); }
_ho1O@<s |4z$1sDIDRt_o{PR H_}z;A9;K74amjb2r O;*89#b!|4w|;z?~ s+EmeTCdpJ9?W8,lNNl| o2#P9R@,hFT {+})BECM.Jf|& // 徹底看不懂,還能夠加上MD5加密