欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java.util.Random和concurrent.ThreadLocalRandom使用對比

 更新時間:2024年07月04日 10:33:14   作者:xindoo  
這篇文章主要介紹了java.util.Random和concurrent.ThreadLocalRandom使用對比,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

java.util.Random和concurrent.ThreadLocalRandom對比

最近工作中遇到了一個需求

需要以一定的概率過濾掉一部分的流量,想想只能用Random了,因為是在多線程環(huán)境下,我還特意確認(rèn)了下Random在多線程是否能正常運行,Random的實現(xiàn)也比較簡單,初始化的時候用當(dāng)前的事件來初始化一個隨機數(shù)種子,然后每次取值的時候用這個種子與有些MagicNumber運算,并更新種子。

最核心的就是這個next的函數(shù),不管你是調(diào)用了nextDouble還是nextInt還是nextBoolean,Random底層都是調(diào)這個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));
    }

為了保證多線程下每次生成隨機數(shù)都是用的不同

next()得保證seed的更新是原子操作,所以用了AtomicLong的compareAndSet(),該方法底層調(diào)用了sum.misc.Unsafe的compareAndSwapLong(),也就是大家常聽到的CAS, 這是一個native方法,它能保證原子更新一個數(shù)?! ?/p>

既然Random滿足我的需求,又能在多線程下正常運行,所以我直接用了random,后來在codeReview中,同事提出用concurrent.ThreadLocalRandom來替代Random。

我腦子里立馬冒出一個問題,既然random是線程安全的,為什么concurrent包里還要實現(xiàn)一個random。

在oracle的jdk文檔里發(fā)現(xiàn)這樣一句話:

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更適合用在多線程下,能大幅減少多線程并行下的性能開銷和資源爭搶?! ?/p>

既然文檔里說的牛,到底能有多少的性能提升?

我做了一個簡單的測試。

測試環(huán)境:

24核 CPU, jdk8,每個隨機生成100000個double數(shù),分別測試不同線程數(shù)下rando和ThreadLocalRandom的運行時間,數(shù)據(jù)如下:

這里寫圖片描述

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

ThreadLocalRandom雖然也有波動,但基本上是平的,而random隨著線程數(shù)的增加一直在增加,在1000個線程時兩者居然有百倍的性能差距。

不過這里有個讓人百思不得其解的現(xiàn)象,為什么random的耗時在500個線程的時候又掉下來,測試多次都是這個情況,可見并不是偶發(fā)現(xiàn)象。

我也在本人的筆記本上測了下,我筆記本雙核i7,ThreadLocalRandom和Random性能差距最高也有100倍,我發(fā)現(xiàn)我筆記本比公司服務(wù)器跑的快(數(shù)據(jù)如下)。。。。

我也在一臺1核的阿里云ECS上測試了,按道理1核心的技術(shù)上,即便是多線程起始也是串行執(zhí)行的,但ThreadLocalRandom和Random在1000個線程的情況下也有6倍的性能差距。

  這里寫圖片描述

既然ThreadLocalRandom在多線程下表現(xiàn)這么牛,它究竟是如何做到的?

我們來看下源碼,它的核心代碼是這個:

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

起始ThreadLocalRandom是對每個線程都設(shè)置了單獨的隨機數(shù)種子,這樣就不會發(fā)生多線程同時更新一個數(shù)時產(chǎn)生的資源爭搶了,用空間換時間?! ?/p>

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

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java實現(xiàn)圖片上插入文字并保存

    java實現(xiàn)圖片上插入文字并保存

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)圖片上插入文字并保存,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Java多線程之讀寫鎖分離設(shè)計模式

    Java多線程之讀寫鎖分離設(shè)計模式

    這篇文章主要介紹了Java多線程讀寫鎖分離設(shè)計模式,主要利用Java到嗎完成read read 并行化、read write 不允許、write write 不允許幾項任務(wù),需要的朋友可以參考一下
    2021-10-10
  • mybatis中批量插入的兩種方式(高效插入)

    mybatis中批量插入的兩種方式(高效插入)

    MyBatis是一個支持普通SQL查詢,存儲過程和高級映射的優(yōu)秀持久層框架。這篇文章主要介紹了mybatis中批量插入的兩種方式(高效插入)的相關(guān)資料,非常不錯,具有參考借鑒價值,感興趣的朋友一起看看吧
    2016-09-09
  • Spring Cloud多個微服務(wù)之間調(diào)用代碼實例

    Spring Cloud多個微服務(wù)之間調(diào)用代碼實例

    這篇文章主要介紹了Spring Cloud多個微服務(wù)之間調(diào)用代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • IDEA創(chuàng)建Java Web項目不能及時刷新HTML或JSP頁面問題

    IDEA創(chuàng)建Java Web項目不能及時刷新HTML或JSP頁面問題

    這篇文章主要介紹了IDEA創(chuàng)建Java Web項目不能及時刷新HTML或JSP頁面問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • JPA原生SQL實現(xiàn)增刪改查的示例詳解

    JPA原生SQL實現(xiàn)增刪改查的示例詳解

    JPA除了對JPQL提供支持外,還對原生SQL語句也提供了支持。本文將利用生SQL實現(xiàn)增刪改查功能,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-09-09
  • SpringBoot?Security使用MySQL實現(xiàn)驗證與權(quán)限管理

    SpringBoot?Security使用MySQL實現(xiàn)驗證與權(quán)限管理

    安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring?Security基本配置
    2022-11-11
  • Java多邊形重心計算

    Java多邊形重心計算

    今天小編就為大家分享一篇關(guān)于Java多邊形重心計算,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 使用XSD校驗Mybatis的SqlMapper配置文件的方法(1)

    使用XSD校驗Mybatis的SqlMapper配置文件的方法(1)

    這篇文章以前面對SqlSessionFactoryBean的重構(gòu)為基礎(chǔ),簡單的介紹了相關(guān)操作知識,然后在給大家分享使用XSD校驗Mybatis的SqlMapper配置文件的方法,感興趣的朋友參考下吧
    2016-11-11
  • SpringCloud整合OpenFeign實現(xiàn)微服務(wù)間的通信

    SpringCloud整合OpenFeign實現(xiàn)微服務(wù)間的通信

    微服務(wù)之間的通信?式,通常有兩種: RPC 和 HTTP,在SpringCloud中, 默認(rèn)是使?HTTP來進?微服務(wù)的通信, 最常?的實現(xiàn)形式有兩種:RestTemplate和OpenFeign,本文給大家介紹了SpringCloud整合OpenFeign實現(xiàn)微服務(wù)間的通信,需要的朋友可以參考下
    2024-06-06

最新評論