1. 程式人生 > >java7新特性——使用ThreadLocalRandom產生併發隨機數

java7新特性——使用ThreadLocalRandom產生併發隨機數

Java 7之前我們使用Math.random()產生隨機數,使用原子變數來儲存當前的種子,這樣兩個執行緒同時呼叫序列時得到的是偽隨機數,而不是相同數量的兩倍。

ThreadLocalRandom是JDK 7之後提供併發產生隨機數,能夠解決多個執行緒發生的競爭爭奪。ThreadLocalRandom不是直接用new例項化,而是第一次使用其靜態方法current()。

從Math.random()改變到ThreadLocalRandom有如下好處:

我們不再有從多個執行緒訪問同一個隨機數生成器例項的爭奪。

取代以前每個隨機變數例項化一個隨機數生成器例項,我們可以每個執行緒例項化一個。

一個隨機變數例項化一個隨機數生成器,隨機變數可以被多個執行緒訪問,就可能出現兩個執行緒同時訪問隨機變數生成隨機數的狀況,得到的就不是真正的隨機數;;而每個執行緒例項化一個隨機數生成器,也避免了上述問題

程式碼改變如下:

// Random random = new Random(100);  random1.nextDouble();
double u = ThreadLocalRandom.current().nextDouble();

效能對比

使用Math.random()的結果如下:

StopWatch 'Monte Carlo NPV': running time (millis) = 44637
-----------------------------------------
ms % Task name
-----------------------------------------
12202 027% Sequential
02576 006% DivideByTwo (children=2, min fork size=100)
02465 006% DivideByTwo (children=2, min fork size=500)
02615 006% DivideByTwo (children=2, min fork size=1000)
02515 006% DivideByTwo (children=2, min fork size=2000)
02502 006% DivideByP (children=8, min fork size=100)
02490 006% DivideByP (children=8, min fork size=500)
02445 005% DivideByP (children=8, min fork size=1000)
02450 005% DivideByP (children=8, min fork size=2000)
02477 006% Sqrt(n) (children=-1, min fork size=100)
02458 006% Sqrt(n) (children=-1, min fork size=500)
02466 006% Sqrt(n) (children=-1, min fork size=1000)
02468 006% Sqrt(n) (children=-1, min fork size=2000)
02508 006% Parfor (children=20000, min fork size=500)

使用ThreadLocalRandom.current().nextDouble()結果:

StopWatch 'Monte Carlo NPV': running time (millis) = 34942
-----------------------------------------
ms % Task name
-----------------------------------------
11347 032% Sequential
02004 006% DivideByTwo (children=2, min fork size=100)
01831 005% DivideByTwo (children=2, min fork size=500)
01838 005% DivideByTwo (children=2, min fork size=1000)
01784 005% DivideByTwo (children=2, min fork size=2000)
01781 005% DivideByP (children=8, min fork size=100)
01782 005% DivideByP (children=8, min fork size=500)
01772 005% DivideByP (children=8, min fork size=1000)
01776 005% DivideByP (children=8, min fork size=2000)
01781 005% Sqrt(n) (children=-1, min fork size=100)
01788 005% Sqrt(n) (children=-1, min fork size=500)
01805 005% Sqrt(n) (children=-1, min fork size=1000)
01799 005% Sqrt(n) (children=-1, min fork size=2000)
01854 005% Parfor (children=20000, min fork size=500)

足足提高了25%。ThreadLocalRandom用時更少

正如StringBuffer和StingBuilder一樣,通過將執行緒安全放入其初始化部分,而不是在使用階段,這就能夠得到效能提升,另外一個例子是ThreadLocal和synchronized,synchronized是在程式碼使用時加上同步,而使用ThreadLocal是每個執行緒一個例項,避免使用共享要引入同步。