引子:需要實現每天隨機獲得一個禮包,且全服玩家隨出來的都是同一個。
實現方案:以當前時間是一年的第幾天作爲random的種子,取1~禮包總個數範圍內的隨機值。
public static int getBuffId() { Calendar c = Calendar.getInstance(); c.setTimeInMillis(System.nanoTime()); int dateInYear = c.get(Calendar.DAY_OF_YEAR); return new Random(dateInYear).nextInt(10) + 1; }
於是決定深入瞭解一下隨機數的種子。
Random兩種構造方法。一種是無參構造函數。種子是 ++seedUniquifier + System.nanoTime(), 所以每新new一個Random實例,種子都會變。
private static volatile long seedUniquifier = 8682522807148012L; public Random() { this(++seedUniquifier + System.nanoTime()); }
另一種是設置種子的構造方法。
public Random(long seed) { this.seed = new AtomicLong(0L); setSeed(seed); }
看一下next()方法。每次調用next()方法。種子就會發生變化 nextseed = (oldseed * multiplier + addend) & mask;
private final static long multiplier = 0x5DEECE66DL; private final static long addend = 0xBL; private final static long mask = (1L << 48) - 1;
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));//保證oldseed跟nextseed不相同 return (int)(nextseed >>> (48 - bits)); }
public int nextInt() { return next(32); }
實例:
//實例1 Random random = new Random(1000); for (int i = 1; i < 4; i++) { System.out.println(random.nextInt()); } System.out.println("..........."); //實例2 for (int j = 0; j < 4; j++) { System.out.println(new Random(1000).nextInt()); }
運行結果:
1487836800000 -1244746321 1060493871 -1826063944 ........... -1244746321 -1244746321 -1244746321 -1244746321
分析:運行結果不一樣。原因如下:
實例1設定了種子1000,for循環裏,nextSeed一直在變,所以隨出來的值也每次不一樣。
實例2每次new一個新的Random對象,每次seed都會被重置成1000,後面調用nextInt() 算出來的nextSeed都是同一個值,所以不管循環幾次,隨出來的結果都一樣。