HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的,让我们从源码的角度上来进行分析。
1. 声明的区别
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
//ConcurrentHashMap的声明
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
implements ConcurrentMap<K, V>, Serializable
//hashmap的声明
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
Hashtable继承了Dictionary类,实现了Map接口,提供了clone方法。
ConcurrentHashMap继承了AbstractMap类,实现了ConcurrentMap接口。
HashMap继承了AbstractMap类,实现了Map接口,提供了clone方法。
三者之间最大的差别在于实现了不同的接口ConcurrentMap和Map。
再看看ConcurrentMap。
public interface ConcurrentMap<K, V> extends Map<K, V>
小结:在一定的程度上可以理解为Hashtable在提供的方法上与HashMap并无不同,ConcurrentHashMap则提供了更多的方法,或者说功能更加强大。
2.方法的区别
从最为常用的方法来看,即get和put。
public V get(Object key){
}
public V put(K key, V value) {
}
public synchronized V get(Object key){
}
public synchronized V put(K key, V value) {
}
public V get(Object key) {
}
public V put(K key, V value){
}
小结:ConcurrentHashMap与HashMap没有区别。HashTable则在方法级别上加入了同步锁synchronized,并且读写都有。由此可以看出HashTable虽然解决了线程安全的问题,但是性能却是急剧下降的。
3.数据结构的区别
private transient Entry[] table;
private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
final K key;
V value;
Entry next;
}
transient Entry[] table = (Entry[]) EMPTY_TABLE;
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry next;
int hash;
}
final Segment[] segments;
transient volatile HashEntry[] table;
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry next;
}
小结:HashMap的数据结构与HashTable一致,ConcurrentHashMap则是维护着多个HashMap。
4.数据操作的区别
public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry 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();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
Entry e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
hashmap和hashtable的put操作是一样的,此处不再做讲解,传送门java1.7集合源码赏析系列:HashMap
public V put(K key, V value) {
Segment s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment)UNSAFE.getObject
(segments, (j <null