ConcurrentHashMap

ConcurrentHashMap

ConcurrentHashMap与HashMap的区别 HashMap是线程不安全的,在多线程的环境下,使用HashMap的put方法会引起死循环,导致CPU的使用率接近100% HashTable HashTable与hashmap的实现类似,但是HashTable不允许key和value为nu

ConcurrentHashMap与HashMap的区别

HashMap是线程不安全的,在多线程的环境下,使用HashMap的put方法会引起死循环,导致CPU的使用率接近100%

HashTable

HashTable与hashmap的实现类似,但是HashTable不允许key和value为null

HashTable是线程安全的,但是HashTable线程安全的策略实现代价太大了,get/put所有相关操作都是synchronized的,相当于给整个哈希表加了把大锁。
多线程访问的时候,只要有一个线程方位或者操作该对象,那么其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景会非常的差。

ConcurrentHashMap

该集合主要是为了应对hashMap在并发环境中不安全而诞生的。大量使用了Volatile,final,CAS等lock-free技术来减少锁竞争对于性能的影响。

Map一般是通过数组+链表的结构(JDK1.8之后为数组和红黑树)

ConcurrentHashMap避免对整个集合都加锁,改成局部加锁操作。

JDK1.7中的ConcurrenthashMapd的实现原理

采用数组+Segment+分段锁的方式实现。

Segment(分段锁)--减少锁的粒度

segment,类似HashMap的结构,即内部拥有一个Entry数组,数组中的每隔元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)

内部结构

concurentHashMap使用分段所技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程方位,实现并发访问。

从上述结构中,我们能看出,concurrentHashMap定位一个元素的过程需要进习两次Hash操作。

第一次Hash定位到Segment,第二次Hash定位到元素所在的链表头部。

结构的优劣势

坏处:这种结构的副作用是Hash的过程要比普通的HashMap要长。

好处:写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment。这样,在最理想的情况下,concurrenthashMap可以最高同时支持Segment数量大小的写操作(这些写操作正好对应每一个Segment)。

1.8中的实现原理

ConcurrentHashMap参考了JDK8 Hash Map的实现,采用了数组+链表+红黑树的实现方式来设计,内部采取大量的CAS操作。

CAS操作即 compara and swap 比较交换。
JDK8中放弃使用Segment,使用Node,设计思想也不再是JDK1.7中的分段锁思想。

Node:

保存key,value以及key的hash值的数据结构。其中value和next都用volatile修饰,保证并发的可见性。

class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;
    //... 省略部分代码
}

结构上与1.8的Hashmap基本一样,不过保证线程安全了。

由于ConcurrentHashMap引入红黑树的结构,使得其实现变得复杂,我们都知道,红黑树是一种性能非常好的二叉排序树。

总结

相比较1.8中的HashMap,这两者的结构已经非常相近了,只是ConcurrentHashMap只是增加了同步的操作来控制并发。

从JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本的Synchronized+CAS+HashEntry+红黑树。

1、数据结构:取消了Segment分段锁的数据结构,使用了数组+链表+红黑树的结构。

2、保证线程安全机制:JDK1.7使用Segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8则是通过CAS+Synchronized来保证线程安全。

3、锁的粒度:原本是对每个Segment加锁,现在是对每隔数组元素加锁(Node)

4、链表准换为红黑树:定位节点的Hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转换成红黑树进行存储。

5、查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)

LICENSED UNDER CC BY-NC-SA 4.0
Comment