??今天來(lái)和大家嘮嘮HashTable,平時(shí)編碼的時(shí)候沒(méi)用過(guò)它,記憶中它和HashMap一樣是進(jìn)行key-value存儲(chǔ)的,數(shù)據(jù)結(jié)構(gòu)也一樣,但是HashMap不是線程安全的,HashTable是線程安全的。今天我們就來(lái)剖析一下它,因?yàn)楹虷ashMap相似,所以對(duì)比著來(lái)看。
真的想吐槽下:Hashtable 為啥不是HashTable[捂臉]
一、相同之處
- HashMap和HashTable數(shù)據(jù)結(jié)構(gòu)是一致的。內(nèi)部都是一個(gè)Entry<K,V>的數(shù)組。
private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
final K key;
V value;
Entry<K,V> next;
protected Entry(int hash, K key, V value, Entry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
- 內(nèi)部成員變量一致。loadFactor threshold modCount count(HashMap中數(shù)量用size表示)在Hashtable中均有。
- 同HashMap一樣,當(dāng)count>=threshold時(shí)就需要進(jìn)行擴(kuò)容了。
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
......
}
二、不同之處
- Hashtable初始化時(shí),默認(rèn)的容量是11,負(fù)載因子是0.75,且初始化的時(shí)候就會(huì)為Entry<K,V>數(shù)組申請(qǐng)。
public Hashtable() {
this(11, 0.75f);
}
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]; //申請(qǐng)table數(shù)組空間
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
initHashSeedAsNeeded(initialCapacity);
}
- HashMap能存儲(chǔ)key為null的情況,Hashtable不能存儲(chǔ)key為null的。
- 擴(kuò)容機(jī)制不同。HashMap每次resize的時(shí)候,容量會(huì)擴(kuò)容為原來(lái)的2倍,Hashtable會(huì)擴(kuò)容為原來(lái)的2倍+1(為保證奇數(shù))
- HashMap不是線程安全的(具體原因見(jiàn):http://m.itdecent.cn/p/c92e0e279243),Hashtable是線程安全的。實(shí)現(xiàn)的方式是通過(guò)在方法上加synchronized鎖,如下:
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提供的所有方法都加上了synchronized鎖。雖然保證了線程安全,但同時(shí)我們也發(fā)現(xiàn),在每個(gè)方法上都加了這個(gè)同步鎖,在多并發(fā)的情況下,效率是很低的。