聶永的博客

          記錄工作/學習的點點滴滴。

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

          ThreadLocalRandom是一個可以獨立使用的、用于生成隨機數的類。繼承自Random,但性能超過Random,所謂“青出于藍而勝于藍”。其API所提供方法,不多,父類Random具有的,它也一樣具有。從表明看,是一個單例模式,其實不然:
          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進行包裝的Random子類,每線程對應一個ThreadLocalRandom實例。測試代碼:
          @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(),不錯。
          @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);
          }
          非規范的性能測試,某次輸出結果:
          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();
          }
          很奇怪,性能為什么差那么遠呢?可能個各自的next函數不同造成。看一下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));
          }
          而ThreadLocalRandom的重寫版本為:
          protected int next(int bits) {  
          rnd = (rnd * multiplier + addend) & mask;
          return (int) (rnd >>> (48-bits));
          }
          相比ThreadLocalRandom的next(int bits)函數實現上更為簡練,不存在seed的CAS操作,并且少了很多的運算量。
          更為詳細的機制研讀,請閱讀參考資料中鏈接。
          另外,ThreadLocalRandom 也提供了易用的,兩個數字之間的隨機數生成方式。類似于:
          nextDouble(double least, double bound)
          nextInt(int least, int bound)
          nextLong(long least, long bound)
          隨機數的生成范圍為 最小值 <= 隨機數 < 最大值??梢园钚≈?,但不包含最大值。
          @Test
          public void testHowtoUse(){
          final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
          final int MAX = 100;
          int result = threadLocalRandom.nextInt(0, 100);
          Assert.assertTrue(MAX > result);
          }
          嗯,還有,不支持setSeed方法。
          曾經JDK 7中,ThreadLocalRandom 存在隨機多個線程隨機數生成相同的bug,但最新版本中,已不存在,被修復了,可以放心使用。從現在開始,完全可以使用ThreadLocalRandom替代Random,尤其是在并發、并行、多任務等環境下,會比在多線程環境下使用公共共享的Random對象實例更為有效。
          代碼清單:

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

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

          公告

          所有文章皆為原創,若轉載請標明出處,謝謝~

          新浪微博,歡迎關注:

          導航

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

          統計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 灌南县| 丹寨县| 石棉县| 正安县| 武定县| 衡阳县| 彰化市| 黎川县| 九龙坡区| 乌兰县| 友谊县| 民县| 湖北省| 乐至县| 丹巴县| 仁寿县| 鹤庆县| 英德市| 浦县| 桐柏县| 九寨沟县| 正安县| 江西省| 馆陶县| 宜宾县| 信丰县| 青龙| 铜鼓县| 定州市| 巴南区| 安远县| 江孜县| 逊克县| 四川省| 江华| 绥中县| 诸暨市| 全南县| 怀集县| 丽江市| 藁城市|