ThreadLocalRandom使用

【譯文】,作者:baeldung, 原文鏈接:https://www.baeldung.com/java-thread-local-random

譯文地址:github, 如有問題,歡迎指正。

綜述

生成隨機數(shù)是很常見的任務。 這也是 JAVA 提供 Random 的原因。但是它在多線程環(huán)境中性能并不高。

簡單來說,Random 之所以在多線程環(huán)境中性能不高的原因是多個線程共享同一個 Random 實例并進行爭奪。

為了解決這個限制,JAVA 在 JDK 7 中引入了 ThreadLocalRandom 類,用于在多線程環(huán)境下生產隨機數(shù)。

ThreadLocalRandom 強于 Random

ThreadLocalRandom 結合了 RandomThreadLocal 類,并被隔離在當前線程中。因此它通過避免任何對 Random 對象的并發(fā)訪問,從而在多線程環(huán)境中實現(xiàn)了更好的性能。

一個線程獲取到的隨機數(shù)不受另一個線程影響,而 Random 提供全局的隨機數(shù)。

另外,不同于 Random, ThreadLocalRandom 明確的不支持設置隨機種子。 它重寫了 Random
setSeed(long seed) 方法并直接拋出了 UnsupportedOperationException 異常。

現(xiàn)在讓我們來看看幾種生產隨機 int、long、double 的方式。

使用 ThreadLocalRandom 生產隨機數(shù)

根據(jù) Oracle 的文檔,我們只需要調用 ThreadLocalRandom.current() 方法,它就會返回當前線程的 ThreadLocalRandom 的實例。
然后我們就可以調用這個實例的方法獲取隨機數(shù)

讓我們生成一個沒有任何限制的 int

int unboundedRandomValue = ThreadLocalRandom.current().nextInt());

現(xiàn)在再生成一個有界的 int, 即介于兩個數(shù)之間。

這是一個生成 0 ~ 100 的 int 值的例子

int boundedRandomValue = ThreadLocalRandom.current().nextInt(0, 100);

請注意:0 是包含在界限內, 而 100 是不在范圍內的。

我們可以使用與示例中相似的方式,調用 nextLong()nextDouble() 方法來生產 longdouble 值。

JAVA 8 還添加了一個 nextGaussian() 方法來生成正態(tài)分布的值,與生成器序列生成的值偏差 0.0 ~ 1.0 。

Random 類一樣,我們可以使用 doubles(), ints(), longs()方法來生成隨機數(shù)流。

使用 JMH 比較

讓我們來看看怎樣在多線程環(huán)境下使用這兩個類來獲取隨機數(shù),并使用 JMH 比較性能。

首先, 讓我們創(chuàng)建一個多個線程共享一個 Random 實例的例子。
我們提交使用 Random 實例生成隨機數(shù)的任務至 ExecutorService 中:

ExecutorService executor = Executors.newWorkStealingPool();
List<Callable<Integer>> callables = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 1000; i++) {
    callables.add(() -> {
         return random.nextInt();
    });
}
executor.invokeAll(callables);

接下來使用 JMH benchmarking 來檢測上述代碼的性能:

# Run complete. Total time: 00:00:36
Benchmark                                            Mode Cnt Score    Error    Units
ThreadLocalRandomBenchMarker.randomValuesUsingRandom avgt 20  771.613 ± 222.220 us/op

相似的,現(xiàn)在讓我們使用 ThreadLocalRandom 代替 Random

ExecutorService executor = Executors.newWorkStealingPool();
List<Callable<Integer>> callables = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
    callables.add(() -> {
        return ThreadLocalRandom.current().nextInt();
    });
}
executor.invokeAll(callables);

下面是 ThreadLocalRandom 的測試結果:

# Run complete. Total time: 00:00:36
Benchmark                                                       Mode Cnt Score    Error   Units
ThreadLocalRandomBenchMarker.randomValuesUsingThreadLocalRandom avgt 20  624.911 ± 113.268 us/op

最后比較上面的測試結果, 我們可以清晰的看到生成 1000 個隨機數(shù),Random 耗時 772 毫秒, 而 ThreadLocalRandom 耗時 625 毫秒。

因此,我們可以得出 ThreadLocalRandom 在高并發(fā)環(huán)境下更有效率

為了學習 JMH, 可以參考之前的文章

結論

本文講述了 RandomThreadLocalRandom 之間的區(qū)別。

我們也看到了在 ThreadLocalRandomThreadLocalRandom 在多線程環(huán)境下的優(yōu)勢和性能,以及如何使用等。

ThreadLocalRandom 是 JDK 的一個簡單補充,但是能在高并發(fā)應用中產生顯著的影響。

然后,跟往常一樣,所有的示例都可以在 GitHub project 中看到。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容