ConcurrentHashMap
学习了ArrayList与HashSet相对应的线程安全的CopyOnWriteArrayList 与CopyOnWriteArraySet之后,今天学习HashMpa对应的线程安全集合ConcurrentHashMap.
HashMap是线程不安全的,HashTable是线程安全的。但是HashTable是通过Synchronized进行同步的,这就导致一个线程占有锁,其它不管读写线程都需要等待,效率地下。
ConcurrentHashMap就解决这个问题。HashTable是把整个链表进行加锁,ConcurrentHashMap就是通过缩小锁的粒度来解决。
ConcurrentHashMap结构
从结构图中,对比,HashTable中维护的是一个链表,而在ConCurrentHashMap中,不是直接维护一个Hash链表,而是在中间加入了一个Segment(段)的概念。每个Segment去维护一个Hash链表。ConcurrentHashMap就是靠这个段来缩小锁的粒度。也就是说,ConcurrentHashMap把真个链表拆成多个Segment,由他们来各自维护一个链表,这样当要进行操作时,只需要操作对应的Segment就可以,而不需要像HashTable一样操作的是一个整体的链表。
优点
缩小的锁的粒度,这样大大增加了并发的能力
缺点
定位到具体的对象,需要进过两次Hash运算。第一次定位到段,再定位到链表头部。这样hash的过程要比HashTable长。
Segment
static final class Segment<K,V> extends ReentrantLock implements Serializable {
transient volatile int count; //Segment中元素的数量
transient int modCount; //对table的大小造成影响的操作的数量
transient int threshold;//Segment扩容的阀值
transient volatile HashEntry<K,V>[] table;//链表数组,数组中的每一个元素代表了一个链表的头部
final float loadFactor;//负载因子
}
HashEntry
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;