多線程之Map:Hashtable HashMap 以及ConcurrentHashMap的線程安全問題

一、Map體系
參考:http://java.chinaitlab.com/line/914247.html
Hashtable是JDK 5以前Map惟一線程安全的內置實現(Collections.synchronizedMap不算)。Hashtable繼承的是 Dictionary(Hashtable是其惟一公開的子類),並不繼承AbstractMap或者HashMap.儘管Hashtable和 HashMap的結構很是相似,可是他們之間並無多大聯繫。
ConcurrentHashMap是HashMap的線程安全版本,ConcurrentSkipListMap是TreeMap的線程安全版本。
最終可用的線程安全版本Map實現是ConcurrentHashMap/ConcurrentSkipListMap/Hashtable /Properties四個,可是Hashtable是過期的類庫,所以若是能夠的應該儘量的使用ConcurrentHashMap和 ConcurrentSkipListMap.html

二、Hashtable、HashMap異同java

(1)Hashtable是Dictionary的子類數組

代碼以下:
public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable

HashMap:
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable安全

HashMap和Hashtable都是Map接口的一個實現類;多線程

(2)Hashtable中的方法是同步的(),而HashMap中的方法在默認狀況下不是同步的。便是說,在多線程應用程序中,不用專門的操做就安全地 可使用Hashtable了;而對於HashMap,則須要額外的同步機制。但HashMap的同步問題可經過Collections的一個靜態方法得 到解決:app

public static Map synchronizedMap(Map m)ide

這個方法返回一個同步的Map,也就是說返回的Map是線程安全的。須要注意的是,對返回的map進行迭代時,必須手動在返回的map上進行同步,不然將會致使不肯定的行爲:性能

Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}this

(3)在HashMap中,null能夠做爲鍵,這樣的鍵只有一個;能夠有一個或多個鍵所對應的值爲null。線程

當get()方法返回null值時,便可以表示HashMap中沒有該鍵,也能夠表示該鍵所對應的值爲null。所以,在HashMap中不能由 get()方法來判斷HashMap中是否存在某個鍵,而應該用containsKey()方法來判斷。Hashtable的鍵值不能爲null,否 則:java.lang.NullPointerException 。

(4)HashTable使用Enumeration,HashMap使用Iterator。
以上只是表面的不一樣,它們的實現也有很大的不一樣。

(5)HashTable中hash數組默認大小是11,增長的方式是 old*2+1。HashMap中hash數組的默認大小是16,並且必定是2的指數。

(6)哈希值的使用不一樣,HashTable直接使用對象的hashCode,代碼是這樣的:

代碼以下:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

而HashMap從新計算hash值,並且用與代替求模,好比HashMap的put方法

代碼以下:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

modCount++;
addEntry(hash, key, value, i);
return null;
 }
代碼以下:

static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
 }
代碼以下:

static int indexFor(int h, int length) {
return h & (length-1);
}

總之,HashTable是多線程安全的,不須要人工同步,但性能方面會差一點;而HashMap不能直接用於多線程。而

ConcurrentHashMap的出現正解決上訴問題。它是HashMap的線程安全版本,性能方面也優於HashTable。ConcurrentSkipListMap是TreeMap的線程安全版本。

相關文章
相關標籤/搜索