java.util.Random和concurrent.ThreadLocalRandom對比

      網友投稿 650 2025-04-07

      最近工作中遇到了一個需求,需要以一定的概率過濾掉一部分的流量,想想只能用Random了,因為是在多線程環境下,我還特意確認了下Random在多線程是否能正常運行,Random的實現也比較簡單,初始化的時候用當前的事件來初始化一個隨機數種子,然后每次取值的時候用這個種子與有些MagicNumber運算,并更新種子。最核心的就是這個next的函數,不管你是調用了nextDouble還是nextInt還是nextBoolean,Random底層都是調這個next(int bits)。


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

      1

      2

      3

      4

      5

      6

      7

      8

      9

      為了保證多線程下每次生成隨機數都是用的不同,next()得保證seed的更新是原子操作,所以用了AtomicLong的compareAndSet(),該方法底層調用了sum.misc.Unsafe的compareAndSwapLong(),也就是大家常聽到的CAS, 這是一個native方法,它能保證原子更新一個數。

      既然Random滿足我的需求,又能在多線程下正常運行,所以我直接用了random,后來在codeReview中,同事提出用concurrent.ThreadLocalRandom來替代Random。我腦子里立馬冒出一個問題,既然random是線程安全的,為什么concurrent包里還要實現一個random。在oracle的jdk文檔里發現這樣一句話

      use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention. Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools.

      大意就是用ThreadLocalRandom更適合用在多線程下,能大幅減少多線程并行下的性能開銷和資源爭搶。

      既然文檔里說的牛逼,到底能有多少的性能提升?我做了一個簡單的測試。測試環境:24核 CPU, jdk8,每個隨機生成100000個double數,,分別測試不同線程數下rando和ThreadLocalRandom的運行時間,數據如下

      ThreadNum,Random,ThreadLocalRandom 50,1192,575 100,4031,162 150,6068,223 200,8093,287 250,10049,248 300,12346,200 350,14429,212 400,16491,62 450,18475,96 500,11311,97 550,12421,90 600,13577,102 650,14718,111 700,15896,127 750,17101,129 800,17907,203 850,19261,226 900,21576,151 950,22206,147 1000,23418,174

      java.util.Random和concurrent.ThreadLocalRandom對比

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      ThreadLocalRandom雖然也有波動,但基本上是平的,而random隨著線程數的增加一直在增加,在1000個線程時兩者居然有百倍的性能差距。不過這里有個讓人百思不得其解的現象,為什么random的耗時在500個線程的時候又掉下來,測試多次都是這個情況,可見并不是偶發現象。

      我也在本人的筆記本上測了下,我筆記本雙核i7,ThreadLocalRandom和Random性能差距最高也有100倍,我發現我筆記本比公司服務器跑的快(數據如下)。。。。我也在一臺1核的阿里云ECS上測試了,按道理1核心的技術上,即便是多線程起始也是串行執行的,但ThreadLocalRandom和Random在1000個線程的情況下也有6倍的性能差距。

      既然ThreadLocalRandom在多線程下表現這么牛逼,它究竟是如何做到的?我們來看下源碼,它的核心代碼是這個

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

      1

      2

      3

      4

      5

      6

      起始ThreadLocalRandom是對每個線程都設置了單獨的隨機數種子,這樣就不會發生多線程同時更新一個數時產生的資源爭搶了,用空間換時間。

      最后附上Random和ThreadLocalRandom的性能測試代碼

      import Java.util.Random; import Java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; public class RandomTest { private static Random random = new Random(); private static final int N = 100000; // Random from java.util.concurrent. private static class TLRandom implements Runnable { @Override public void run() { double x = 0; for (int i = 0; i < N; i++) { x += ThreadLocalRandom.current().nextDouble(); } } } // Random from java.util private static class URandom implements Runnable { @Override public void run() { double x = 0; for (int i = 0; i < N; i++) { x += random.nextDouble(); } } } public static void main(String[] args) { System.out.println("threadNum,Random,ThreadLocalRandom"); for (int threadNum = 50; threadNum <= 2000; threadNum += 50) { ExecutorService poolR = Executors.newFixedThreadPool(threadNum); long RStartTime = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { poolR.execute(new URandom()); } try { poolR.shutdown(); poolR.awaitTermination(100, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } String str = "" + threadNum +"," + (System.currentTimeMillis() - RStartTime)+","; ExecutorService poolTLR = Executors.newFixedThreadPool(threadNum); long TLRStartTime = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { poolTLR.execute(new TLRandom()); } try { poolTLR.shutdown(); poolTLR.awaitTermination(100, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(str + (System.currentTimeMillis() - TLRStartTime)); } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      Java 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel數字乘法函數的使用教程
      下一篇:Excel2019不連續單元格快速輸入相同內容的方法
      相關文章
      亚洲激情在线观看| 亚洲妓女综合网99| 亚洲av片不卡无码久久| 久久精品视频亚洲| 亚洲中文字幕第一页在线| 四虎亚洲国产成人久久精品| 人人狠狠综合久久亚洲| 亚洲av永久无码精品网址 | 欧美日韩亚洲精品| 亚洲av无码专区在线电影| 亚洲高清中文字幕免费| 亚洲午夜精品久久久久久app| 亚洲国产精品精华液| 亚洲熟妇无码av另类vr影视| 亚洲熟女乱色一区二区三区| 亚洲AV成人精品一区二区三区| 在线观看亚洲免费视频| 亚洲欧洲日本在线| 亚洲中文字幕日产乱码高清app| 国产V亚洲V天堂无码| 亚洲欧洲在线观看| 亚洲成年人免费网站| 久久久久亚洲国产| 亚洲avav天堂av在线网毛片| 亚洲精品色婷婷在线影院| 亚洲日韩欧洲无码av夜夜摸| 久久精品视频亚洲| 78成人精品电影在线播放日韩精品电影一区亚洲 | 亚洲精品国产高清不卡在线| 国产亚洲精品成人a v小说| 亚洲国产精品国自产拍AV| 亚洲最大福利视频网站| 亚洲va在线va天堂va手机| 精品亚洲国产成人| 亚洲欧洲国产综合AV无码久久| 国产亚洲精品欧洲在线观看| 亚洲色精品vr一区二区三区| 久久亚洲精品成人av无码网站| 亚洲一区免费在线观看| 久久亚洲精品无码gv| 久久久久噜噜噜亚洲熟女综合|