原文网址:ConcurrentHashMap--原理\_IT博客-CSDN博客其他网址辉的博客-CSDN博客ConcurrentHashMap源码分析(JDK8版)\_我什么都希望-CSDN博客Hashmap1.7和1.8区别+ConcurrentHashmap1.7和1.8的区别_hellodake的博客-CSDN博客介绍JDK7和JDK8的区别> Item JDK1.8 机制 ReentrantLock+Segment+HashEntry(数组加链表) synchronized+CAS+HashEntry(数组加链表)+红黑树 读操作:volatile;写操作:synchronized+CAS?/p>/td> Granularity 锁定需要数据操作的Segment 锁定每个桶(数组项)p>JDK1.7 JDK7在JDK1.7中,ConcurrentHashMap采用ReentrantLock+Segment+HashEntry(数组加链表)的方式来实现,ConcurrentHashMap中的段锁称为Segment,类似于HashMap的结构,即内部有一个Entry数组,并且数组中的每一项第一个元素同时是一个链表和一个ReentrantLock(Segment继承ReentrantLock)。ConcurrentHashMap使用段锁技术将数据分成段存储,然后为每个段数据分配一个锁。当一个线程占用锁访问一段数据时,其他段的数据也可以被其他线程访问。实现真正的并发访问。ConcurrentHashMapput流程内部结构图第一次对key进行hash,通过hash值确定Segment的位置在Segment中进行操作,获取锁并获取当前Segment的HashEntry数组,然后进行第二次对key进行hash,通过hash值确定Segment中位置HashEntry数组的索引位置(头),通过继承ReentrantLock的tryLock方法尝试获取锁。如果获取成功,则直接插入相应位置。如果一个线程已经获取到Segment的锁,则当前线程会自旋继续调用tryLock方法获取锁,指定次数后挂起,等待唤醒然后遍历HashEntry链当前索引,如果有重复键,则替换;如果没有重复键,则将其插入链头释放锁get操作与put操作类似,同样需要两次哈希。但是get操作的concurrenthashmap不需要加锁,因为存储元素都标记为volatile。size操作size操作就是遍历两次所有的Segment,记录每次Segment的modCount值,然后比较两次的modCount。如果相同,则说明该期间没有发生写操作,返回原来遍历的结果。如果判断两次统计的modCount不一致,则必须锁住所有segment,获取并统计count。这期间,每个段都被锁定,不能进行其他操作,计算出来的count自然是准确的。这种结构的优缺点优点写操作时,只能锁定元素所在的Segment,不会影响其他Segment。缺点Hash的过程比普通的HashMap长。JDK8概述JDK8中ConcurrentHashMap的结构与HashMap基本相同。读操作使用CAS,写操作使用synchronized。在JDK8中,Segment被彻底抛弃,取而代之的是Node,其设计思想不再是JDK1.7中的segmentlock思想。节点:一种数据结构,保存了key的key,value,以及key的hash值。其中value和next都用volatile修饰,保证并发的可见性。classNode
