HashTable —— 線程安全的散列表
阿新 • • 發佈:2017-10-04
機制 iter nth already size set 映射 city hold
HashTable 的一些認識:
- 底層使用散列表,存貯鍵值對,鍵值非null
- 使用synchronize 保證線程安全
- 如果多線程高發量,推薦使用 concurrentHashMap;如無需多線程,可使用 HashMap
■ 重要全局變量
//The hash table data. //底層維護一個Entry(鍵值對)數組 private transient Entry<K,V>[] table;
//The total number of entries in the hash table. //元素總量,等同於HashMap的size private transientint count;
//The load factor for the hashtable. //負載因子 private float loadFactor;
/** * The table is rehashed when its size exceeds this threshold. * (The value of this field is (int)(capacity * loadFactor).) * 超過閾值進行rehash */ private int threshold; /** * The number of times this Hashtable has been structurally modified * Structural modifications are those that change the number of entries in * the Hashtable or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the Hashtable fail-fast. (See ConcurrentModificationException). * 結構性變動時modCount計數+1,用於遍歷時的fail-fast機制生效*/ private transient int modCount = 0
■ 構造函數
/** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor. */ public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; //沒有強調2次冪,cap為0時,默認是1 this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } /** * Constructs a new, empty hashtable with a default initial capacity (11) * and load factor (0.75). * 容量11,負載因子 0.75 */ public Hashtable() { this(11, 0.75f); }
■主要方法
- put(K key, V value)
public synchronized V put(K key, V value) { // Make sure the value is not null,而HashMap選擇將key為null永遠存放為table[0]位置 if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. //確保key不在hashtable中 //首先,通過hash方法計算key的哈希值,並計算得出index值,確定其在table[]中的位置 //其次,叠代index索引位置的鏈表,如果該位置處的鏈表存在相同的key,則替換value,返回舊的value Entry tab[] = table; int hash = hash(key); //計算下標,這裏使用%方法,性能遠不及HashMap的位運算 (這也是不推薦使用HashTable的原因之一) int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { //直接使用equals比較,而HashMap多了一層地址比較 `((k = e.key) == key || key.equals(k))` if ((e.hash == hash) && e.key.equals(key)) { V old = e.value; e.value = value; return old; } }
//結構性變更操作 modCount計數+1 modCount++; //HashMap選擇新增addEntry方法封裝一下邏輯 if (count >= threshold) { // Rehash the table if the threshold is exceeded //如果超過閥值,就進行rehash操作 rehash(); tab = table; hash = hash(key); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. //將值插入,返回的為null Entry<K,V> e = tab[index]; // 創建新的Entry節點,並將新的Entry插入Hashtable的index位置,並設置e為新的Entry的下一個元素 tab[index] = new Entry<>(hash, key, value, e); //size++ count++; return null; }
- get(Object key)
public synchronized V get(Object key) { Entry tab[] = table; //臨時拷貝,保證數據的時效性 int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; }
■ HashTable 遍歷
/** * Created by roman on 2017/10/03. *【2017 java‘s day】 */ public class ListHashTableTest { public static void main(String[] args) { Hashtable<String, Object> hb = new Hashtable<String, Object>(); hb.put("1", "Java"); hb.put("flag", true); hb.put("age", 44); Iterator iterator = hb.keySet().iterator(); iterator.forEachRemaining(value -> System.out.println(hb.get(value))); //使用了lamda } }
■ HashTable VS HashMap
- HashTable 基於 Dictionary 類,而 HashMap 是基於 AbstractMap。Dictionary 是任何可將鍵映射到相應值的類的抽象父類,而 AbstractMap 是基於 Map 接口的實現,它以最大限度地減少實現此接口所需的工作.
- HashMap 的 key 和 value 都允許為 null,而 Hashtable 的 key 和 value 都不允許為 null。HashMap 遇到 key 為 null 的時候,調用 putForNullKey 方法進行處理(統一放入table[0]位置),而對 value 沒有處理;Hashtable遇到 null,直接返回 NullPointerException.
- Hashtable 方法是同步,而HashMap則不是。Hashtable 中的幾乎所有的 public 的方法都是 synchronized 的,而有些方法也是在內部通過 synchronized 代碼塊來實現。
- HashTable由於使用sync和%運算(以及相關算法實現)的緣故,相比於HashMap,性能較低,因此非常不推薦繼續使用HashTable。
- 非競爭環境下推薦使用HashMap。
- 多線程環境下推薦使用ConcurrentHashMap。
HashTable —— 線程安全的散列表