一些工具类的原理
# 一些工具类的原理
# concurrenthashmap
# 结构
在Java JDK1.8之后,它是由数组、单向链表和红黑树来构成的。当我们就初始化一个concurrenthashmap的实例的时候,默认会初始化一个长度等于16的数组。
由于concurrenthashmap它的核心仍然是哈希表,所以必然会存在哈希冲突的问题。所以hashmap采用链式寻址的方式来解决哈希表的冲突。当哈希冲突比较多的时候,会造成链表长度较长的问题。所以这种情况下会使得concurrent hash map中的一个数组元素的查询复杂度会增加。
所以在JDK1.8里面引入了红黑树这样一个机制。当数组长度大于64,并且链表的长度大于等于8的时候,单向链表就会转化成红黑素。另外随着concurrenthashmap的一个动态扩容,一旦链表的长度小于8,红黑树会退化成单向链表。
# 线程安全的实现
第二个,concurrent hash map的一个基本功能。Concurrent hash map本质上是一个hashmap,因此功能和hashmap是一样的。但是concurrenthashmap在hashmap的基础上提供了并发安全的一个实现。
并发安全的主要实现主要是通过对于node节点去加锁,来保证数据更新的安全性。
# 锁的优化
在JDK1.7 之前,它锁定的是segment,是一个分段锁的概念。每个 Segment
都是一个小型的哈希表,并且有自己的锁。这样可以允许多个线程同时访问不同的 Segment
,从而提高并发性能。但这种锁的范围要很大,所以性能上它会较低。
JDK1.8之后,锁粒度变为了————每个数组元素(称为桶)都有自己的锁,而不是整个 Segment
。这样可以进一步减少锁的竞争,提高并发性能。广泛使用 CAS 操作来实现无锁的更新操作,例如插入、删除和更新等。
此外,在扩容方面concurrenthashmap还做了两个点的优化。
第一个点是当线程竞争不激烈的时候,直接采用CAS的方式来实现元素个数的一个原子递增。第二个,如果线程竞争比较激烈的情况下,使用一个数组来维护元素个数。如果要增加总的元素个数的时候,直接从数组中随机选择一个,再通过CAS算法来实现原子递增。