深入分析IntHashMap

 一、IntHashMap

   1.1 準備

  先從官網下載jar包:javasoft-collection.jar,解壓後將jar包build到Java項目中.

  1.2 IntHashMap類圖

  1.3 IntHashMap流程圖

  

   從上面類圖可以看出IntHashMap和HashMap一樣都是基於Map接口,在Map中最常用的2個方法是put()和get()方法。大家都知道Map是從鍵到值的映射,每個鍵不能出現重複且每個鍵最多隻能映射到一個值。那麼IntHashMap是如何保證鍵的唯一性?可能大家會想IntHashMap的鍵是int類型,使用==來比較,這樣子雖然能保證鍵的唯一。但是隨着元素的增加,每次都進行比較效率會越來越低。什麼樣的數據結構能快速的存儲元素?答案是數組。HashMap中是通過hash計算出bucketIndex位置找到數組中對應的元素,那麼IntHashMap呢?IntHashMap亦如此,唯一不同的是計算bucketIndex的算法通過indexFor()方法拿到bucketindex後。它會先去數組中找這個位置上的元素IntEntry<V>是否存在,如果存在的話,再通過key去查找value,然後將新值替換掉舊value。
代碼清單2如下:

[java] view plain copy
  1. /** 
  2.    * Returns index for key 
  3.    */  
  4.   protected int indexFor(int key, int length) {  
  5. key += ~(key << 9);  
  6. key ^=  (key >>> 14);  
  7. key +=  (key << 4);  
  8. key ^=  (key >>> 10);  
  9. return key & (length-1);  
  10.   }  
 代碼清單3如下:

[java] view plain copy
  1. int i = indexFor(key, table.length);  
  2.   
  3. for (IntEntry<V> e = table[i]; e != null; e = e.next) {  
  4.        if (e.key == key) {  
  5.              V oldValue = e.value;  
  6.              e.value = value;  
  7.              e.recordAccess(this);  
  8.              return oldValue;  
  9.         }  
  10. }  

 二、IntHashMap與HashMap比較

   2.1 運行效率比較

  創建一個測試類,分別往IntHashMap和HashMap各插入1萬和5萬條數據來測試它們性能、GC和內存使用

[java] view plain copy
  1. package com.lll.operator;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import ch.javasoft.util.intcoll.IntHashMap;  
  7.   
  8. public class ShiftTest {  
  9.   
  10.     //  IntHashMap<String> map = new IntHashMap<String>();  
  11.     HashMap<Integer,String> map = new HashMap<Integer,String>();  
  12.   
  13.     public void add()  
  14.     {  
  15.         for (int i = 0; i < 10000;i++) {  
  16.             for(int j = 0;j<50000;j++)  
  17.             {  
  18.                 if(map.get(j) == null)  
  19.                 {  
  20.                     map.put(j, "小毛驢");  
  21.                 }  
  22.             }  
  23.         }  
  24.     }  
  25.     public static void main(String[] args) {  
  26.         long curTime = System.currentTimeMillis();  
  27.         ShiftTest shiftTest = new ShiftTest();  
  28.         shiftTest.add();  
  29.         long curTime2 = System.currentTimeMillis();  
  30.         System.out.println("耗時:"+(curTime2-curTime)+"ms");  
  31.         try {  
  32.             Thread.sleep(5000);  
  33.         } catch (InterruptedException e) {  
  34.             // TODO Auto-generated catch block  
  35.             e.printStackTrace();  
  36.         }  
  37.     }  
  38.   
  39. }  

   2.2 Visual GC比較

  HashMap:

  IntHashMap:

   2.3 結果分析

10000條數據測試結果:
Map類型 第一次取樣 第二次取樣 第三次取樣 GC
IntHashMap 795ms 815ms 807ms NO GC
HashMap 866ms 927ms 861ms 11.978ms

 50000條數據測試結果:
Map類型 第一次取樣 第二次取樣 第三次取樣 GC時間
IntHashMap 5166ms 4817ms 4997ms NO GC
HashMap 4388ms 4430ms 3876ms 40.453ms

    從上面的測試結果可以看出,HashMap會隨着容器大小的變化效率明顯變慢。也許從數據測試結果來看使用IntHashMap在性能上比HashMap並沒有太大優勢甚至效率還要低些,但是從GC上來看明顯IntHashMap更有優勢。那麼是什麼讓他們產生這樣的差異?

   2.4 差異一

  HashMap在插入元素過程中會在堆中產生大量的Integer實例(如下圖-Profiler界面),參考代碼清單4。而IntHashMap不一樣,它是以int作爲key值類型(見代碼清單5),能夠減少Integer實例的產生,減少GC負擔。

  Profiler界面


代碼清單4:

[java] view plain copy
  1. static class Entry<K,V> implements Map.Entry<K,V> {  
  2.        final K key;  
  3.        V value;  
  4.        Entry<K,V> next;  
  5.        int hash;  
  6.   
  7.        /** 
  8.         * Creates new entry. 
  9.         */  
  10.        Entry(int h, K k, V v, Entry<K,V> n) {  
  11.            value = v;  
  12.            next = n;  
  13.            key = k;  
  14.            hash = h;  
  15.        }  

代碼清單5:

[java] view plain copy
  1. public static class IntEntry<VV> implements IntMap.IntEntry<VV> {  
  2.         protected final int key;  
  3.         protected VV value;  
  4.         protected IntEntry<VV> next;  
  5.   
  6.         /** 
  7.          * Create new entry. 
  8.          */  
  9.         protected IntEntry(int k, VV v, IntEntry<VV> n) {  
  10.             value = v;  
  11.             next = n;  
  12.             key = k;  
  13.         }  

   2.5 差異二

 在遍歷時,IntHashMap(代碼清單6)沒有對hash進行比較。

 代碼清單6

[java] view plain copy
  1. public V get(int key) {  
  2.         int i = indexFor(key, table.length);  
  3.         IntEntry<V> e = table[i];   
  4.         while (true) {  
  5.             if (e == null)  
  6.                 return null;  
  7.             if (e.key == key)   
  8.                 return e.value;  
  9.             e = e.next;  
  10.         }  
  11.     }  
 HashMap遍歷代碼清單7
[java] view plain copy
  1. final Entry<K,V> getEntry(Object key) {  
  2.         int hash = (key == null) ? 0 : hash(key);  
  3.         for (Entry<K,V> e = table[indexFor(hash, table.length)];  
  4.              e != null;  
  5.              e = e.next) {  
  6.             Object k;  
  7.             if (e.hash == hash &&  
  8.                 ((k = e.key) == key || (key != null && key.equals(k))))  
  9.                 return e;  
  10.         }  
  11.         return null;  
  12.     }  



作者:小毛驢,一個遊戲人 
夢想:世界和平   
原文地址:http://blog.csdn.net/liulongling
文章如有錯誤之處,還請見諒並能給予指正!     
本博客中未標明轉載的文章歸作者小毛驢所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章