@pastqing
2018-01-23T19:25:28.000000Z
字数 1210
阅读 1407
java
java-collection-framwork
ConcurrentHashMap是一个线程安全的hashmap,相比于使用synchronized加锁实现线程安全的HashTable, 前者更加高效。
ConcurrentHashMap包含两个基本的静态类HashEntry和Segment。HashEntry用来存储key-value,Segment用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶。每个桶是由若干个HashEntry 对象链接起来的链表。一个 ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组。
结构图如下:
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next;
HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
final void setNext(HashEntry<K,V> n) {
UNSAFE.putOrderedObject(this, nextOffset, n);
}
// Unsafe mechanics
static final sun.misc.Unsafe UNSAFE;
static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class k = HashEntry.class;
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
注意到value被声明为volatile,这样保证写线程对value域的写入后续的读线程会马上看到,即volatile的语义:写线程的对value的写可以被不加锁的读线程看到,提高了性能。
在JDK1.6中,next
字段被声明为final
类型,也就是发生冲突时默认采用头插法来给冲突链表添加新的结点。同时使用final
也会保证在容器在多线程环境下,读线程正在读的元素不会因为其他写线程正在写而发生错读, 脏读。
JDK1.7中,next
字段被声明为volatile