之前分析過(guò)HashMap的結(jié)構(gòu),接下來(lái)簡(jiǎn)單的分析一下HashTable的數(shù)據(jù)結(jié)構(gòu)和線程安全的實(shí)現(xiàn)。
HashTable實(shí)現(xiàn)上與HashMap實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)相似,先看HashTable定義:
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
它實(shí)現(xiàn)了Map接口,與HashMap不一樣的是,他繼承了Dictionary。那么接下來(lái)看一下他的主要成員變量:
private transient Entry<K,V>[] table;
private transient int count;
private int threshold;
private float loadFactor;
與HashMap類似,他擁有一個(gè)hash的表table數(shù)組,同時(shí)定義了裝載因子loadFactor,初始化桶容量threshold,接下來(lái)看一下HashTable重寫(xiě)的Entry:
private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
final K key;
V value;
Entry<K,V> next;
...
}
與HashMap類似的他將Entry定義為一個(gè)存儲(chǔ)key-map的鏈表結(jié)構(gòu)。那么我們可以繼續(xù)仿照HashMap去理解HashTable的結(jié)構(gòu)。
接下來(lái),我們看一下HashTable中的put方法:
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 = 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)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}
第一眼看上去,好長(zhǎng),而且在一個(gè)方法內(nèi)實(shí)現(xiàn)了大部分的邏輯,可以看出,HashTable在實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)層面上沒(méi)有HashMap的精煉,算法層面上也沒(méi)有HashMap寫(xiě)的優(yōu)。一部分原因是這部分代碼實(shí)現(xiàn)在JDK1.0中,另一方面,是為了保持操作的原子性,保證線程安全??梢钥吹?,HashTable在實(shí)現(xiàn)線程安全方面,通過(guò)將讀寫(xiě)操作代碼整合在一個(gè)方法中,通過(guò)synchronized來(lái)達(dá)到線程互斥,保證線程安全。
那么看一下HashTable中還有哪些通過(guò)synchronized聲明的方法:
synchronized void clear()
synchronized Object clone()
synchronized boolean contains(Object value)
synchronized boolean containsKey(Object key)
synchronized boolean containsValue(Object value)
synchronized Enumeration<V> elements()
synchronized Set<Entry<K, V>> entrySet()
synchronized boolean equals(Object object)
synchronized V get(Object key)
synchronized int hashCode()
synchronized boolean isEmpty()
synchronized Set<K> keySet()
synchronized Enumeration<K> keys()
synchronized V put(K key, V value)
synchronized void putAll(Map<? extends K, ? extends V> map)
synchronized V remove(Object key)
synchronized int size()
synchronized String toString()
synchronized Collection<V> values()
通過(guò)分析put方法大致發(fā)現(xiàn)了HashTable在實(shí)現(xiàn)線程安全方面采取了一些有別于HashMap的方式,其他的方法可以大致參考HashMap的解釋,就懶一下,不分析了。