基本的容器类,我们已经分析完了,虽然感觉自己的分析一般,但是,还是有些收获的。
这一篇,分析一个线程安全的容器,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,就被淘汰了(过时了)。