聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          Fork/Join模式(JSR166y)手記之ThreadLocalRandom

          ThreadLocalRandom是一個(gè)可以獨(dú)立使用的、用于生成隨機(jī)數(shù)的類。繼承自Random,但性能超過Random,所謂“青出于藍(lán)而勝于藍(lán)”。其API所提供方法,不多,父類Random具有的,它也一樣具有。從表明看,是一個(gè)單例模式,其實(shí)不然:
          private static final ThreadLocal localRandom =
          new ThreadLocal() {
          protected ThreadLocalRandom initialValue() {
          return new ThreadLocalRandom();
          }
          };

          ThreadLocalRandom() {
          super();
          initialized = true;
          }


          public static ThreadLocalRandom current() {
          return localRandom.get();
          }
          采用ThreadLocal進(jìn)行包裝的Random子類,每線程對(duì)應(yīng)一個(gè)ThreadLocalRandom實(shí)例。測(cè)試代碼:
          @Test
          public void testInstance() {
          final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
          final List randomList = new ArrayList();
          final Phaser barrier = new Phaser(1);

          new Thread() {
          @Override
          public void run() {
          randomList.add(ThreadLocalRandom.current());
          barrier.arrive();
          }
          }.start();

          barrier.awaitAdvance(barrier.getPhase());
          if (randomList.isEmpty()) {
          throw new NullPointerException();
          }

          Assert.assertTrue(threadLocalRandom != randomList.get(0));
          }
          這么一包裝,在性能上可以趕超Math.random(),不錯(cuò)。
          @Test
          public void testSpeed() {
          final int MAX = 100000;
          ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

          long start = System.nanoTime();
          for (int i = 0; i < MAX; i++) {
          threadLocalRandom.nextDouble();
          }
          long end = System.nanoTime() - start;
          System.out.println("use time1 : " + end);

          long start2 = System.nanoTime();
          for (int i = 0; i < MAX; i++) {
          Math.random();
          }
          long end2 = System.nanoTime() - start2;
          System.out.println("use time2 : " + end2);

          Assert.assertTrue(end2 > end);
          }
          非規(guī)范的性能測(cè)試,某次輸出結(jié)果:
          use time1 : 3878481
          use time2 : 8633080
          性能差別不止兩倍啊,哈哈。
          再看Math.random(),其生成也是依賴于Random類:
          private static Random randomNumberGenerator;

          private static synchronized void initRNG() {
          if (randomNumberGenerator == null)
          randomNumberGenerator = new Random();
          }

          public static double random() {
          if (randomNumberGenerator == null) initRNG();
          return randomNumberGenerator.nextDouble();
          }
          很奇怪,性能為什么差那么遠(yuǎn)呢?可能個(gè)各自的next函數(shù)不同造成。看一下Random中的next(int bits)方法實(shí)現(xiàn):
          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));
          }
          而ThreadLocalRandom的重寫版本為:
          protected int next(int bits) {  
          rnd = (rnd * multiplier + addend) & mask;
          return (int) (rnd >>> (48-bits));
          }
          相比ThreadLocalRandom的next(int bits)函數(shù)實(shí)現(xiàn)上更為簡(jiǎn)練,不存在seed的CAS操作,并且少了很多的運(yùn)算量。
          更為詳細(xì)的機(jī)制研讀,請(qǐng)閱讀參考資料中鏈接。
          另外,ThreadLocalRandom 也提供了易用的,兩個(gè)數(shù)字之間的隨機(jī)數(shù)生成方式。類似于:
          nextDouble(double least, double bound)
          nextInt(int least, int bound)
          nextLong(long least, long bound)
          隨機(jī)數(shù)的生成范圍為 最小值 <= 隨機(jī)數(shù) < 最大值。可以包含最小值,但不包含最大值。
          @Test
          public void testHowtoUse(){
          final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
          final int MAX = 100;
          int result = threadLocalRandom.nextInt(0, 100);
          Assert.assertTrue(MAX > result);
          }
          嗯,還有,不支持setSeed方法。
          曾經(jīng)JDK 7中,ThreadLocalRandom 存在隨機(jī)多個(gè)線程隨機(jī)數(shù)生成相同的bug,但最新版本中,已不存在,被修復(fù)了,可以放心使用。從現(xiàn)在開始,完全可以使用ThreadLocalRandom替代Random,尤其是在并發(fā)、并行、多任務(wù)等環(huán)境下,會(huì)比在多線程環(huán)境下使用公共共享的Random對(duì)象實(shí)例更為有效。
          代碼清單:

          參考資料:
          1. Java 7: How to write really fast Java code

          posted on 2012-02-04 11:29 nieyong 閱讀(1578) 評(píng)論(0)  編輯  收藏 所屬分類: Java

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2012年2月>
          2930311234
          567891011
          12131415161718
          19202122232425
          26272829123
          45678910

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 桃园县| 丹凤县| 车险| 吉首市| 东乌珠穆沁旗| 龙海市| 加查县| 板桥市| 房山区| 大港区| 温州市| 商都县| 广水市| 珠海市| 颍上县| 靖江市| 双城市| 买车| 台江县| 广饶县| 广昌县| 手机| 水富县| 嵊州市| 乐东| 汝州市| 西藏| 察雅县| 乐业县| 巴青县| 乌兰浩特市| 古田县| 苏尼特左旗| 丹巴县| 珲春市| 长垣县| 桐梓县| 平原县| 田东县| 沐川县| 麦盖提县|