基本的容器类,我们已经分析完了,虽然感觉自己的分析一般,但是,还是有些收获的。
这一篇,分析一个线程安全的容器,Hashtable,大家都知道,使线程安全的方法就那几种,而Hashtable就是用了线程安全的最简单的方法(一个关键字),synchronize关键字。将方法锁住,其他任何线程都无法进入。其实这种做法的效率及其地下,也逐渐被替代了。到现在,HashTable已经过时了,jdk源码中的注释中也说明了不要在使用HashTable了。
If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use java.util.concurrent.ConcurrentHashMap in place of Hashtable.
HashTable的底层也是一个散列表。
先看一下Hashtable的定义。继承了Dictionary,实现了Map
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable
public abstract class Dictionary<K,V> { public Dictionary() { } abstract public int size(); abstract public boolean isEmpty(); abstract public Enumeration<K> keys(); abstract public Enumeration<V> elements(); abstract public V get(Object key); abstract public V put(K key, V value); abstract public V remove(Object key); }
我们可以看到Dictionary,就是一个抽象类,其他方法都是抽象方法。
private transient Entry<?,?>[] table;//数组 private transient int count;//实际容量 private int threshold;//极限容量 private float loadFactor;//装填因子 private transient int modCount = 0; /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1421746759512286392L; 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); } public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } public Hashtable() { this(11, 0.75f); } public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }
看一下HashTable中节点结构的定义:
/* *链表中的节点结构 */ private static class Entry<K,V> implements Map.Entry<K,V> { final 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; } @SuppressWarnings("unchecked") protected Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } public int hashCode() { return hash ^ Objects.hashCode(value); } public String toString() { return key.toString()+"="+value.toString(); } }
HashTable也是一个散列表,添加和获取元素,都要定位桶的位置,定位桶的位置和HashMap的方法不一样
HashMap--》hash(key)&(table.length-1)
HashTable--》(hash(key) & 0x7FFFFFFF) %tab.length
其实,在看HashTable的源码时,已经没有什么压力了,所以我就不写了,打击自己看一下就行了,毕竟HashTable也已经过时了。
其实,HashTable在复合操作中也可能线程不安全。
所以,等等原因,HashTable,就被淘汰了(过时了)。