转载自:https://blog.csdn.net/weixin_40616523/article/details/86419754 https://blog.csdn.net/qq_41931837/article/details/82314478

1.ConcurrentHashMap

        ConcurrentHashMap使用分段锁保证线程安全,效率比使用synchronized的HashTable高很多,每个集合都可以看做一个存储东西的房子,HashTable与ConcurrentHashMap存储的都是HashEntry数组(每个数组里面是链表)。         HashTable:在HashTable这个房子里,只有一个房间,里面是一长列的存放Entry的货架(数组)。只要有一个人进了这个房间,就会把这个房间锁起来,知道这个人在房间里面做完了事情出来后才会把们打开。如果有其他人需要进去,只能等待。这会导致外面等了很多人,效率不高。         ConcurrentHashMap:在ConcurrentHashMap这个房子里,有很多房间,每个房间都存储着Entry货架(Entry数组的不同段,将一整个Entry数组分开了),这些房间各自又有着不同的锁。一个人在访问某一个房间时,会把这个房间锁起来,其他房间依然可以进去,这样可以大大提升效率。

        在HashTable中:线程A想访问Entry数组前面的位置,线程B想访问Entry数组后面的位置,如果A先进去了,房子就会被锁住,B不得不等待。         在ConcerrentHashMap中:线程A想访问Entry数组前面的位置,线程B想访问Entry数组后面的位置,A进到了前面元素所在的房间访问,B仍然可以去尾部元素所在的房间,他们处在不同的房间。

2.分段锁

        分段锁其实是以重锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。         ConcurrentHashMap中的分段锁称为Segment,类似于JDK7和JDK8中HashMap的实现的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)。         当需要put元素时,并不是对整个hashmap进行加锁,而是通过hashcode知道放在哪一个分段中,然后对这个分段进行加锁,所以当多线程put时,只要不是放在一个分段中,就实现了真正的并行插入。但是         先分段再锁,将原来的一整个的Entry数组分成了若干段,分别将这若干段放在了不同的新的Segment数组中(分房间),每个Segment有各自的锁,以此提高效率。但是在统计size的时候,是获取hashmap全局信息的时候,就需要获取所有分段锁才能统计。

3.分段锁应用场景

        当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。         分段锁设计的目的是细化锁的粒度。

4.分段锁使用举例