HashMap、HashTable、ConcurrentHashMap 区别

简单总结 HashMap、Hashtable、ConcurrentHashMap 之间的区别,基于 JDK 1.8.0_191

先说结论,暂时有以下几个需要注意的不同点:

  1. 继承、实现接口不同
  2. 初始大小、扩容倍数不同
  3. 线程安全
  4. NULL KEY,NULL VALUE 支持不同
  5. 计算 Hash 值的方式不同

1. 继承、实现接口不同

1
2
3
4
5
6
7
8
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {}

public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
  • HashMap、ConcurrentHashMap 都继承于 AbstractMap 抽象类,但 Hashtable 继承于 Dictionary 抽象类。
  • AbstractMap 实现了 Map 接口,而 Dictionary 没有。这使得 AbstractMap 具有更多的功能,而 Dictionary 逐渐被弃用。

2. 初始大小、扩容倍数不同

HashMap

1
2
3
4
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

扩容部分代码:
newThr = oldThr << 1; // double threshold

Hashtable

1
2
3
4
5
6
public Hashtable() {
this(11, 0.75f);
}

扩容部分代码:
int newCapacity = (oldCapacity << 1) + 1;

ConcurrentHashMap

1
2
3
4
5
/**
* The default initial table capacity. Must be a power of 2
* (i.e., at least 1) and at most MAXIMUM_CAPACITY.
*/
private static final int DEFAULT_CAPACITY = 16;

  • 初始大小:HashMap、ConcurrentHashMap 都是 16,Hashtable 是 11
  • 扩容倍数:HashMap、ConcurrentHashMap 2 倍、Hashtable (2n + 1) 倍。

3. 线程安全

1
2
3
4
5
Hashtable:
public synchronized V put(K key, V value) {}

HashMap:
public V put(K key, V value) {}
  • Hashtable 添加元素方法加上了 synchronized 关键字,HashMap 没有,说明 HashMap 不适用于多线程环境。
  • ConcurrentHashMap 添加元素时,只对需要变更的地方加锁。

4. NULL KEY,NULL VALUE 支持不同

通过观察它们的 put 方法,得到以下结论:

  • Hashtable、ConcurrentHashMap 的 key、value 都不能为 null。
  • HashMap value 可以为 null,而 key 为 null 时,该元素会放在 HashMap 第一位。

5. key 的索引计算方法不同

计算元素存放位置,会经过两步转化。Object -> int -> index,先将 key 使用 hash 方法转换为一个整数数字,然后对整型数字进行转化,得到这个对象在 map 中的索引。

Hashtable

1
2
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

HashMap

1
2
3
4
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

  • Hashtable 直接使用对象的 hashCode,然后再使用除留余数法来获得最终的位置。
  • HashMap 在对象的 hashCode 之上,将 hashCode 的高16位和低16位进行异或,得到最终的位置。

总结

后面学习将对 HashMap,ConcurrentHashMap 源码进行分析总结。

ConcurrentHashMap的扩容机制(jdk1.8)

HashMap 和Hashtable的区别