自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java中生成隨機(jī)數(shù)Random VS ThreadLocalRandom性能比較

開(kāi)發(fā) 前端
本文講解了JDK中提供的兩種生成隨機(jī)數(shù)的方式,一個(gè)是JDK 1.0引入的Random?類,另外一個(gè)是JDK1.7引入的ThreadLocalRandom?類,由于底層的實(shí)現(xiàn)機(jī)制不同,ThreadLocalRandom?的性能是遠(yuǎn)高于Random?,建議后面大家在技術(shù)選型的時(shí)候優(yōu)先使用ThreadLocalRandom。

?前言

大家項(xiàng)目中如果有生成隨機(jī)數(shù)的需求,我想大多都會(huì)選擇使用Random來(lái)實(shí)現(xiàn),它內(nèi)部使用了CAS來(lái)實(shí)現(xiàn)。實(shí)際上,JDK1.7之后,提供了另外一個(gè)生成隨機(jī)數(shù)的類ThreadLocalRandom,那么他們二者之間的性能是怎么樣的呢?

Random的使用

Random類是JDK提供的生成隨機(jī)數(shù)的類, 這個(gè)類不是隨機(jī)的,而是偽隨機(jī)的。什么是偽隨機(jī)呢?偽隨機(jī)是指生成的隨機(jī)數(shù)是有一定規(guī)律的,這個(gè)規(guī)律出現(xiàn)的周期因偽隨機(jī)算法的優(yōu)劣而異。一般來(lái)說(shuō),周期比較長(zhǎng),但可以預(yù)見(jiàn)。我們可以通過(guò)以下代碼簡(jiǎn)單地使用 Random:

圖片

Random中有很多方法。這里我們就分析比較常見(jiàn)的nextInt()和nextInt(int bound)方法。

  • nextInt()會(huì)計(jì)算int范圍內(nèi)的隨機(jī)數(shù),
  • nextInt(int bound)會(huì)計(jì)算[0,bound) 之間的隨機(jī)數(shù),左閉右開(kāi)。

實(shí)現(xiàn)原理

Random類的構(gòu)造函數(shù)如下圖所示:

圖片

可以看到在構(gòu)造方法中,根據(jù)當(dāng)前時(shí)間seed生成了一個(gè)AtomicLong類型的seed。
public int nextInt() {
return next(32);
}

這里面直接調(diào)用了next()方法,傳入了32,這里的32是指Int的位數(shù)。

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));
}

這里會(huì)根據(jù)seed的當(dāng)前值,通過(guò)一定的規(guī)則(偽隨機(jī))計(jì)算出下一個(gè)seed,然后進(jìn)行CAS。如果CAS失敗,繼續(xù)循環(huán)上述操作。最后根據(jù)我們需要的位數(shù)返回。

小結(jié):可以看出在next(int bits)?方法中,對(duì)AtomicLong進(jìn)行了CAS操作,如果失敗則循環(huán)重試。很多人一看到CAS,因?yàn)椴恍枰渔i,第一時(shí)間就想到了高性能、高并發(fā)。但是在這里,卻成為了我們多線程并發(fā)性能的瓶頸??梢韵胂?,當(dāng)我們有多個(gè)線程執(zhí)行CAS時(shí),只有一個(gè)線程一定會(huì)失敗,其他的會(huì)繼續(xù)循環(huán)執(zhí)行CAS操作。當(dāng)并發(fā)線程較多時(shí),性能就會(huì)下降。

ThreadLocalRandom的使用

JDK1.7之后,提供了一個(gè)新類ThreadLocalRandom?來(lái)替代Random。

圖片

實(shí)現(xiàn)原理

我們先來(lái)看下current()方法。

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);
}

如果沒(méi)有初始化,先進(jìn)行初始化,這里我們的seed不再是全局變量了。我們的線程中有三個(gè)變量:

/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;

/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;

/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
  • threadLocalRandomSeed:這是我們用來(lái)控制隨機(jī)數(shù)的種子。
  • threadLocalRandomProbe:這個(gè)就是ThreadLocalRandom,用來(lái)控制初始化。
  • threadLocalRandomSecondarySeed:這是二級(jí)種子。

關(guān)鍵代碼如下:

UNSAFE.putLong(t = Thread.currentThread(), SEED,r=UNSAFE.getLong(t, SEED) + GAMMA);

可以看出,由于每個(gè)線程都維護(hù)自己的seed?,所以此時(shí)不需要CAS?,直接進(jìn)行put。這里通過(guò)線程間的隔離來(lái)減少并發(fā)沖突,所以ThreadLocalRandom的性能非常高。

性能對(duì)比

通過(guò)基準(zhǔn)工具JMH測(cè)試:

@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iteratinotallow=3, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iteratinotallow=3,time = 5)
@Threads(4)
@Fork(1)
@State(Scope.Benchmark)
public class Myclass {
Random random = new Random();
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

@Benchmark
public int measureRandom(){
return random.nextInt();
}
@Benchmark
public int threadLocalmeasureRandom(){
return threadLocalRandom.nextInt();
}

}

運(yùn)行結(jié)果如下圖所示,最左邊是并發(fā)線程的數(shù)量:

圖片

圖片

顯而易見(jiàn),無(wú)論線程數(shù)量是多少,ThreadLocalRandom?性能是遠(yuǎn)高于Random。

總結(jié)

本文講解了JDK中提供的兩種生成隨機(jī)數(shù)的方式,一個(gè)是JDK 1.0引入的Random?類,另外一個(gè)是JDK1.7引入的ThreadLocalRandom?類,由于底層的實(shí)現(xiàn)機(jī)制不同,ThreadLocalRandom?的性能是遠(yuǎn)高于Random?,建議后面大家在技術(shù)選型的時(shí)候優(yōu)先使用ThreadLocalRandom。

責(zé)任編輯:武曉燕 來(lái)源: JAVA旭陽(yáng)
相關(guān)推薦

2024-05-15 09:09:49

2024-06-24 07:00:00

C++RustGo

2021-04-06 08:54:13

Random線程安全數(shù)生成器

2023-11-19 21:17:58

GoRust

2024-11-01 15:51:06

2011-04-15 10:26:38

JavaMVC

2009-12-02 17:01:01

PHP隨機(jī)數(shù)rand()

2019-09-11 10:09:00

Java虛擬機(jī)算法

2019-05-24 08:48:33

JSONJacksonJSONP

2021-06-15 07:59:01

Java生成隨機(jī)數(shù)Java編程

2010-03-22 19:41:31

2019-04-02 15:07:51

API NginxZuul

2019-12-26 14:07:19

隨機(jī)數(shù)偽隨機(jī)多線程

2009-06-11 15:16:18

不重復(fù)隨機(jī)數(shù)Java

2009-05-25 08:39:08

iPhone蘋果移動(dòng)OS

2017-05-29 09:56:25

2012-03-22 09:31:14

Java

2010-03-11 12:48:25

Python生成隨機(jī)數(shù)

2010-03-10 16:35:23

Python編程語(yǔ)言

2020-07-27 08:24:42

編程語(yǔ)言C語(yǔ)言Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)