新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「一個(gè)程序員的成長(zhǎng)」,作者一個(gè)程序員的成長(zhǎng)。轉(zhuǎn)載本文請(qǐng)聯(lián)系一個(gè)程序員的成長(zhǎng)公眾號(hào)。

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


咨詢(xún)
建站咨詢(xún)
