環境jdk1.8.0_121html
與HashMap有幾點區別(不瞭解HashMap的具體實現,看我另個博客http://www.cnblogs.com/dj3839/p/8111675.html)java
在HashMap中,衝突的值會在bucket造成鏈表,當達到8個,會造成紅黑樹,而在HashTable中,衝突的值就以鏈表的形式存儲數組
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; }
會發現求索引的方式也不同,(hash&0x7FFFFFFF)%tab.length,而在HashMap中是(hash^(hash>>>16))&(tab.length-1),能夠看出HashTable裏,並無作出相應的優化,這邊解釋下HashMap中的優化,(hash^(hash>>>16))這一步是實際上是讓一個hash值的高16位和低16位作異或,混合高位和低位,加大低位的隨機性,(hash^(hash>>>16))&(tab.length-1)求與,其實就是至關於HashTable中的取模,只是在你計算機中用位預算效率比較高,固然tab.length在HashMap中實際上是一個2的n次方,因此能達到這一的效果。安全
還有一點,能夠看到HashTable中是不容許放值爲Null的value,它會拋出錯誤。並且key值也不能爲null,由於它直接拿key.hashCode(),null是拿不到hashCode也會發生錯誤。併發
繼續看addEntry,開始添加元素函數
private void addEntry(int hash, K key, V value, int index) { modCount++; Entry<?,?> tab[] = table; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; }
代碼很是簡潔,若是數量大於限定值,就開始擴充,從新計算索引位置,而後插入高併發
先看插入優化
tab[index] = new Entry<>(hash, key, value, e);
在建立entry的時候,傳了個bucket的第一個entry,this
protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }
看構造函數其實能夠看出,在這裏進行指向舊的第一個entry,所以,在hashtable中實際上是插入在鏈表的頭,而在HashMap是在尾spa
而後咱們在看它的rehash
protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } } }
比HashMap簡單的多。。。len擴充2*len+1,而後對原來bucket中的entry從新計算索引,並賦值,不改變鏈表原先的順序,在HashMap中複雜的多,能夠看我另個講HashMap的博客
並且在hashtable中,調用構造函數時,直接初始化了裏面的數組table,而在hashmap中是在進行put操做時,進行初始化,這個操做也在resize中
能夠看下HashTable中的初始化方法
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; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); }
還有一點,HashTable它的初始化,默認容量len是爲11,後面也是2*len+1擴充,而HashMap是16,之後的擴充數量都是len*2,而且咱們提供容量大小時,也是會轉成一個2的n次方,爲何會有這樣的區分,和它計算hash有關,在前面提到了(hash^(hash>>>16))&(tab.length-1),2^n-1,二進制就是n個1
public Hashtable() { this(11, 0.75f); }
但相對HashMap,HashTable是線程安全的,由於在不少方法,好比get,put,equals等,都使用了synchronized同步鎖。
總結:
1. HashTable的key、value不能爲null
2. HashTable線程安全
3. HashTable的優化其實沒有HashMap作的好,在單線程的狀況,最好使用HashMap
貼上一句源碼中的提示
* Java Collections Framework</a>. Unlike the new collection * implementations, {@code Hashtable} is synchronized. If a * thread-safe implementation is not needed, it is recommended to use * {@link HashMap} in place of {@code Hashtable}. If a thread-safe * highly-concurrent implementation is desired, then it is recommended * to use {@link java.util.concurrent.ConcurrentHashMap} in place of * {@code Hashtable}.
大體意思就是:不須要線程安全用HashMap,須要線程安全的高併發用ConcurrentHashMap