ConcurrentHashMap 简析

2018-11-17  本文已影响21人  wean_a23e

为什么需要 ConcurrentHashMap

Java 早期的同步类 HashTable 和 Collections 提供的同步包装器为我们提供了线程安全的容器,但是因为这两种方式都是在整个大操作 put、get、size 级别上加锁实现的。并发效率很低。作为改进,Java 提供了更为高效的并发容器——ConcurrentHashMap。

jdk 1.7 ConcurrentHashMap 分析

ConcurrentHashMap 的设计其实一直在演化,早期的 ConcurrentHashMap,其实现是基于:

这个版本的核心是利用分段设计,在进行并发操作时,锁住相应的 Segment,来避免锁住整个表,大大提高了性能。

构造时,Segment 的数量由所谓的concurrentcyLevel 决定,默认是 16,可以通过构造函数显式指定,这个输入的值会被 Java 自动调整为最近的 2 的幂数值,比如输入 15,就会被自动调整为 16。之所以这样调整,是因为 2 的幂次方减一就是一个二进制低位全是 1 的“掩码”,在确定元素在哪个 Segment 时会利用到。

在进行并发写操作时:

另一个需要关注的点是 size 方法,它的实现涉及分离锁的一个副作用。

如果不加锁直接计算所有 Segment 的总值,在并发 put 的情况下,就可能导致结果不准确,但是直接锁定所有 Segment 进行计算,代价就很昂贵。其实,分离锁也限制了 Map 的初始化等操作。

这个版本的 ConcurrentHashMap 是通过重试机制(RETRIES_BEFORE_LOCK,指定重试次数 2),来试图获得可靠值。如果没有监控到发生变化(通过对比 Segment.modCount),就直接返回,否则获取锁进行操作。

jdk 1.8 ConcurrentHashMap 分析

上一篇 下一篇

猜你喜欢

热点阅读