ConcurrentHashMap 实现原理

一. ConcurrentHashMap 是什么

在并发编程中,ConcurrentHashMap 是一个经常被使用的数据结构,相比于 Hashtable 以及Collections.synchronizedMap() 来说,ConcurrentHashMap 在线程安全的基础上提供了更好的写并发能力,同时还降低了对读一致性的要求,是 java.util.concurrent 包里面提供的一个线程安全并且高效的 HashMap。

二. ConcurrentHashMap 的不同版本实现

JDK 1.7 中的实现

JDK 1.7 中 的 ConcurrentHashMap 采用了分段锁的设计,只有在同一个分段内才存在竞态关系,不同的分段锁之间没有锁竞争。相比于对整个 Map 加锁,分段锁大大提高了高并发环境下的处理能力。

 如上图所示,ConcurrentHashMap 底层是由一个 Segment 数组组成的,每个 Segment 元素包含一个 HashEntry 数组,而每个 HashEntry 元素都是一个链表结构的节点。

提到 HashEntry,很容易会联想到 HashMap 中的 Entry,它们有什么区别呢?

来看一下 HashEntry 的代码实现:

static final class HashEntry {
        final int hash;
        final K key;
        volatile V value;
        volatile HashEntry next;
}

可以看出,HashEntry 和 HashMap 非常类似,唯一的区别就是其中的核心数据 value 以及 next 都被 volatile 修饰,以此保证了多线程读写过程中对应变量的可见性。 

接下来,我们再来看一下 JDK 1.7 中的 ConcurrentHashMap 的核心方法 put 方法 get 方法 的实现:

put 方法

    public V put(K key, V value) {
        Segment<K,V> s;
        if (value == null)
            throw new NullPointerException();
        // 计算key的hash值
        int hash = hash(key);
        // 根据 hash 值,segmentShift,segmentMask 定位 Segment
        int j = (hash >>> segmentShift) & segmentMask;
        if ((s = (Segment<K,V>)UNSAFE.getObject
             (segments, (j << SSHIFT) + SBASE)) == null)
            s = ensureSegment(j);
        // 将键值对保存到对应的 Segment 中
        return s.put(key, hash, value, false);
    }

可以看到,首先通过 key 定位到 Segment,之后在对应的 Segment 中才会调用具体的 put 方法,对应 put 的源码如下:

    final V put(K key, int hash, V value, boolean onlyIfAbsent) {
        // 如果 tryLock 成功,就返回 null
        // 否则尝试去获取锁,获取锁失败的情况下,为了节约时间提前去新建或获取 HashEntry
        // 如果超过一定次数就强制加锁
        HashEntry<K, V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
        V oldValue;
        try {
            HashEntry<K, V>[] tab = table;
            // 根据table数组的长度和hash值计算index下标
            int index = (tab.length - 1) & hash;
            // 找到table数组在index偏移处链表的头部
            HashEntry<K, V> first = entryAt(tab, index);
            // 从first开始遍历链表
            for (HashEntry<K, V> e = first; ; ) {
                if (e != null) {
                    K k;
                    // 如果key相同
                    if ((k = e.key) == key ||
                            (e.hash == hash && key.equals(k))) {
                        // 
  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盛夏温暖流年

可以赏个鸡腿吃嘛~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值