新聞中心
本文轉載自微信公眾號「一個程序員的成長」,作者一個程序員的成長。轉載本文請聯(lián)系一個程序員的成長公眾號。

創(chuàng)新互聯(lián)建站于2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術服務公司,擁有項目成都做網(wǎng)站、成都網(wǎng)站建設網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元漢中做網(wǎng)站,已為上家服務,為漢中各地企業(yè)和個人服務,聯(lián)系電話:028-86922220
1、Random類及其局限性
- public int nextInt(int bound) {
- if (bound <= 0)
- throw new IllegalArgumentException(BadBound);
- // 計算新的種子
- int r = next(31);
- int m = bound - 1;
- // 根據(jù)新的種子計算隨機數(shù)
- 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;
- }
- protected int next(int bits) {
- long oldseed, nextseed;
- // 這是一個原子性的變量
- AtomicLong seed = this.seed;
- do {
- // (1)、獲取老的種子
- oldseed = seed.get();
- // (2)、計算出新的種子
- nextseed = (oldseed * multiplier + addend) & mask;
- // (3)、CAS操作更新老的種子
- } while (!seed.compareAndSet(oldseed, nextseed));
- return (int)(nextseed >>> (48 - bits));
- }
Random小結:
- 面試:多線程下Random存在什么樣的問題?
每個Random實例里面都有一個原子性的種子變量用來記錄當前的種子值,當要生成新的隨機數(shù)時需要根據(jù)當前的種子計算新的種子并更新種子變量。當在多線程環(huán)境下,多個線程會競爭同一個原子變量的更新操作,由于原子變量的更新時CAS操作,同時只有一個線程會成功,所以會造成大量線程進行自旋重試,從而降低并發(fā)性能。
可能出現(xiàn)的癥狀:如果并發(fā)請求非常多,自旋鎖一直重試,那么CPU會一直飆升。
2、ThreadLocalRandom
- public static ThreadLocalRandom current() {
- if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
- localInit();
- return instance;
- }
- static final void localInit() {
- int p = probeGenerator.addAndGet(PROBE_INCREMENT);
- int probe = (p == 0) ? 1 : p; // skip 0
- long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
- Thread t = Thread.currentThread();
- UNSAFE.putLong(t, SEED, seed);
- UNSAFE.putInt(t, PROBE, probe);
- }
這個方法用來創(chuàng)建ThreadLocalRandom隨機數(shù)生成器,如果當前線程中threadLocalRandomProbe的變量值為0,則說明是第一次調用current方法,那么就調用localInit方法初始化種子變量。
這里使用了延遲初始化,在localInit方法中,并沒有初始化種子變量,而是在需要生成隨機數(shù)的時候再生成種子變量,這是一種優(yōu)化。
- static final void localInit() {
- int p = probeGenerator.addAndGet(PROBE_INCREMENT);
- int probe = (p == 0) ? 1 : p; // skip 0
- long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
- Thread t = Thread.currentThread();
- UNSAFE.putLong(t, SEED, seed);
- UNSAFE.putInt(t, PROBE, probe);
- }
- final long nextSeed() {
- Thread t; long r; // read and update per-thread seed
- // 生成新種子(獲取當前線程種子 + 種子增量)
- UNSAFE.putLong(t = Thread.currentThread(), SEED,
- r = UNSAFE.getLong(t, SEED) + GAMMA);
- return r;
- }
mix32是一個固定的算法,這里重點看下nextSeed方法,當?shù)谝淮握{用的時候進行初始化,獲取當前線程threadLocalRandomSeed的值(第一次默認值為0) + 種子增量,如果不是第一次那么獲取舊種子的值 + 種子增量生成新的種子變量并設置回去。這樣的話多線程環(huán)境下就避免了競爭,因為threadLocalRandomSeed是Thread的一個變量,屬于線程級別。
分享題目:ThreadLocalRandom類原理分析
網(wǎng)頁路徑:http://m.fisionsoft.com.cn/article/dpohecc.html


咨詢
建站咨詢
