一 线程安全
- Hashtable 是线程安全的
- HashMap 不是线程安全的
理由:Hashtable 所有的元素操作都是 synchronized 修饰的,而 HashMap 并没有
public synchronized V put(K key, V value);
public synchronized V get(Object key);
...
二 性能优劣
- Hashtable 是线程安全的,每个方法都要阻塞其他线程,所以Hashtable 性能较差
- HashMap 性能较好,使用更广
建议:如果要线程安全又要保证性能,建议ConcurrentHashMap
三 NULL
- Hashtable 是不允许键或值为null
- HashMap 的键值则都可以为 null
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 = key.hashCode();
...
}
HashMap hash 方法逻辑:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
四 实现方式
- Hashtable 的继承源码:
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
- HashMap 的继承源码:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
五 容量扩容
- HashMap 的初始容量为:16
- Hashtable 初始容量为:11
- 两者的负载因子默认都是:0.75
-
当现有容量大于总容量 * 负载因子时,HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 + 1
/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
*/
public Hashtable() {
this(11, 0.75f);
}
/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
六 迭代器
- HashMap 中的 Iterator 迭代器是 fail-fast 的
- Hashtable 的 Enumerator 不是 fail-fast 的
=》当其他线程改变了HashMap 的结构,如:增加、删除元素,将会抛出 ConcurrentModificationException 异常,而 Hashtable 则不会