Java Random源碼分析

一田篇、Random類的構(gòu)造函數(shù)峦椰,官方文檔如下:

Random類的構(gòu)造函數(shù)

1.無參的構(gòu)造函數(shù)徒扶,源碼如下:

    /**
     * Creates a new random number generator. This constructor sets
     * the seed of the random number generator to a value very likely
     * to be distinct from any other invocation of this constructor.
     */
    public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }

其中seedUniquifier()函數(shù)趣席,個人認為是產(chǎn)生一個隨機數(shù)兵志,System.nanoTime()函數(shù)返回一個納秒級的時間值(這個時間代表什么不重要,此函數(shù)多用來計算流逝的時間宣肚,精度很高想罕,詳見源碼及參考資料),源碼中定義分別如下:

    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;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
        }
    }
    /**
     * Returns the current value of the running Java Virtual Machine's
     * high-resolution time source, in nanoseconds.
     *
     * <p>This method can only be used to measure elapsed time and is
     * not related to any other notion of system or wall-clock time.
     * The value returned represents nanoseconds since some fixed but
     * arbitrary <i>origin</i> time (perhaps in the future, so values
     * may be negative).  The same origin is used by all invocations of
     * this method in an instance of a Java virtual machine; other
     * virtual machine instances are likely to use a different origin.
     *
     * <p>This method provides nanosecond precision, but not necessarily
     * nanosecond resolution (that is, how frequently the value changes)
     * - no guarantees are made except that the resolution is at least as
     * good as that of {@link #currentTimeMillis()}.
     *
     * <p>Differences in successive calls that span greater than
     * approximately 292 years (2<sup>63</sup> nanoseconds) will not
     * correctly compute elapsed time due to numerical overflow.
     *
     * <p>The values returned by this method become meaningful only when
     * the difference between two such values, obtained within the same
     * instance of a Java virtual machine, is computed.
     *
     * <p> For example, to measure how long some code takes to execute:
     *  <pre> {@code
     * long startTime = System.nanoTime();
     * // ... the code being measured ...
     * long estimatedTime = System.nanoTime() - startTime;}</pre>
     *
     * <p>To compare two nanoTime values
     *  <pre> {@code
     * long t0 = System.nanoTime();
     * ...
     * long t1 = System.nanoTime();}</pre>
     *
     * one should use {@code t1 - t0 < 0}, not {@code t1 < t0},
     * because of the possibility of numerical overflow.
     *
     * @return the current value of the running Java Virtual Machine's
     *         high-resolution time source, in nanoseconds
     * @since 1.5
     */
    public static native long nanoTime();

注:其中nanoTime()函數(shù)霉涨,用native關(guān)鍵字修飾按价,由本地代碼實現(xiàn)。

兩者異或運算后笙瑟,初始化類成員變量seed楼镐,此變量會成為隨機函數(shù)的種子,所有的隨機算法都由種子數(shù)算起往枷,定義如下:

    /**
     * The internal state associated with this pseudorandom number generator.
     * (The specs for the methods in this class describe the ongoing
     * computation of this value.)
     */
    private final AtomicLong seed;

2.有參的構(gòu)造函數(shù)框产,源碼如下:

    /**
     * Creates a new random number generator using a single {@code long} seed.
     * The seed is the initial value of the internal state of the pseudorandom
     * number generator which is maintained by method {@link #next}.
     *
     * <p>The invocation {@code new Random(seed)} is equivalent to:
     *  <pre> {@code
     * Random rnd = new Random();
     * rnd.setSeed(seed);}</pre>
     *
     * @param seed the initial seed
     * @see   #setSeed(long)
     */
    public Random(long seed) {
        if (getClass() == Random.class)
            this.seed = new AtomicLong(initialScramble(seed));
        else {
            // subclass might have overriden setSeed
            this.seed = new AtomicLong();
            setSeed(seed);
        }
    }

構(gòu)造函數(shù)由傳入的種子參數(shù)進行初始化,不難理解错洁,值得注意的是秉宿,由同一個種子初始化的Random對象,相同次數(shù)調(diào)用時屯碴,產(chǎn)生的隨機數(shù)相同描睦。舉例如下:

public static void main(String[] args) {
    Random random = new Random(47);
    for(int i = 0; i < 3; i++){
        System.out.print(random.nextInt(20) + " ");
    }
    System.out.println();
    Random randomII = new Random(47);
    for(int i = 0; i < 3; i++){
        System.out.print(randomII.nextInt(20)+ " ");
    }
}

輸出如下:
18 15 13 
18 15 13 

二、Java隨機數(shù)原理

大多數(shù)語言實現(xiàn)偽隨機數(shù)导而,均采用線性同余方程(linear congruential generator)忱叭,詳細內(nèi)容參照「資料1」.
Java中使用的是48-bit的種子,然后調(diào)用線性同余方程嗡载,源碼如下:

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask; //此處為核心窑多,線性同余方程的實現(xiàn)
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

經(jīng)常在隨機數(shù)中調(diào)用的函數(shù)nextInt(),源碼如下:

public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);

    int r = next(31);
    int m = bound - 1;
    if ((bound & m) == 0)  // i.e., bound is a power of 2
        r = (int)((bound * (long)r) >> 31);
    else {
        for (int u = r;
             u - (r = u % bound) + m < 0;
             u = next(31))
            ;
    }
    return r;
}

此處實現(xiàn)應(yīng)該是最新版洼滚,與資料中提供的源碼略有不同埂息,函數(shù)中幾處細節(jié)尚未理解,想清楚之后再回來補充遥巴。


Reference:

  1. 開源中國:Java中的random函數(shù)是如何實現(xiàn)的
  2. System.nanoTime與System.currentTimeMillis的區(qū)別
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末千康,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铲掐,更是在濱河造成了極大的恐慌拾弃,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摆霉,死亡現(xiàn)場離奇詭異豪椿,居然都是意外死亡奔坟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門搭盾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咳秉,“玉大人,你說我怎么就攤上這事鸯隅±浇ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵蝌以,是天一觀的道長炕舵。 經(jīng)常有香客問我,道長跟畅,這世上最難降的妖魔是什么咽筋? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮徊件,結(jié)果婚禮上晤硕,老公的妹妹穿的比我還像新娘。我一直安慰自己庇忌,他們只是感情好舞箍,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著皆疹,像睡著了一般疏橄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上略就,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天捎迫,我揣著相機與錄音,去河邊找鬼表牢。 笑死窄绒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的崔兴。 我是一名探鬼主播彰导,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼敲茄!你這毒婦竟也來了位谋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤堰燎,失蹤者是張志新(化名)和其女友劉穎掏父,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秆剪,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赊淑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年爵政,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陶缺。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡茂卦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出组哩,到底是詐尸還是另有隱情,我是刑警寧澤处渣,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布伶贰,位于F島的核電站,受9級特大地震影響罐栈,放射性物質(zhì)發(fā)生泄漏黍衙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一荠诬、第九天 我趴在偏房一處隱蔽的房頂上張望琅翻。 院中可真熱鬧,春花似錦柑贞、人聲如沸方椎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棠众。三九已至,卻和暖如春有决,著一層夾襖步出監(jiān)牢的瞬間闸拿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工书幕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留新荤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓台汇,卻偏偏與公主長得像苛骨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子苟呐,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 方法1 (數(shù)據(jù)類型)(最小值+Math.random()*(最大值-最小值+1)) 例: (int)(1+Math...
    GB_speak閱讀 40,994評論 2 6
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法智袭,類相關(guān)的語法,內(nèi)部類的語法掠抬,繼承相關(guān)的語法吼野,異常的語法,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 小編費力收集:給你想要的面試集合 1.C++或Java中的異常處理機制的簡單原理和應(yīng)用两波。 當JAVA程序違反了JA...
    八爺君閱讀 4,591評論 1 114
  • 一瞳步、給自己設(shè)限闷哆。“這次數(shù)學考砸了单起,我就是學不好數(shù)學抱怔,女生就是適合讀文科一些”、“我是會計專業(yè)畢業(yè)的嘀倒,我怎么能進營銷...
    圓舞amour閱讀 191評論 1 2
  • 感想(上層餅干): 隨著教育的普及屈留,大家愈來愈知道讀書的重要性。 可能從小到大测蘑,大家都讀過很多書灌危,但是很多內(nèi)容都忘...
    yangxiaoya閱讀 234評論 0 0