ConcurrentHashMap JDK1.7的原理详解

版本JDK 1.7

ConcurrentHashMap的数据结构视图

ConcurrentHashMap的数据结构图

数据结构图解析

上面就是ConcurrentHashMap的数据结构图,对上面的数据结构进行解析,包含的主要元素:

  • Segment
  • table
  • HashEntry
Segment
  static final class Segment<K,V> extends ReentrantLock implements Serializable {

        private static final long serialVersionUID = 2249069246763182397L;

        static final int MAX_SCAN_RETRIES =
            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
            
        transient volatile HashEntry<K,V>[] table;

        transient int count;

        transient int modCount;

        transient int threshold;

        final float loadFactor;

        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
            this.loadFactor = lf;
            this.threshold = threshold;
            this.table = tab;
        }

        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
        
        }

        private void rehash(HashEntry<K,V> node) {
        }

        /**
         * Remove; match on key only if value null, else match both.
         */
        final V remove(Object key, int hash, Object value) {
   
        }

        final boolean replace(K key, int hash, V oldValue, V newValue) {
        }

        final V replace(K key, int hash, V value) {
        }
    }
Segment是ConcurrentHashMap的内部类,同时从上面代码片段中可以看到Segment也是个静态类,同时还继承了ReentrantLock,
说明Segment其实就是一个可重入锁,然后从上面的结构图中可以看到,ConcurrentHashMap里面是一个Segment数组,
然后看了上面的Segment类的主要功能之后,你会发现Segment里面拥有自己HashEntry类型的Table数组,甚至还有threshold和loadfactor
等等,所以你会发现这个Segment其实就要相当于带了锁的HashMap,然后一个Segment数组就相当于是多个带锁的HashMap,
这样如果我们将不同的就相当于将我们的K-V键值对放到了不同的HashMap中,而每个HashMap又带锁。这样就能保证部分K-V在不同的
HashMap中是线程安全的了。

对比我们之前将所有的K-V放到一个HashMap中,这样如果一个线程获得了我们整个HashMap的锁,别的线程就不能操做任何其他的K-V了,
这样锁的粒度比较大,并发性比较低。这里的实现方式就是HashTable的原理(给HashMap加了Synchronized关键字)。
现在ConcurrentHashMap用Segment数组做数据结构, 相当于拥有多个带了锁的HashMap(),然后将原本放到一个HashMap中的数据,
散射到不同的HashMap中,这样当一个线程获取到一个HashMap的锁的时候只会锁定这个HashMap中的数据,
别的线程就可以操作别的HashMap中的数据。

这就是分段锁的原理,

原理很简单:就是我们将原本放到一个HashMap中的键值对,现在分开放到不同的HashMap中,不让鸡蛋放到一个篮子里,
然后给每个HashMap都加锁,这样就可以给多个线程操作了,其实从这里我们可以明白,并发度最高的时候其实就是和我们的HashMap数量有关,
即一个线程操作一个HashMap,
最麻烦的就是我们要封装一下,主要解决我们在put,delete和get的时候映射到哪个HashMap中去做,我们自己做起来可能比较麻烦,
ConcurrentHashMap的主要工作就是做了这些操作。具体的细节可以看源代码,有了这么一个大的框架做背景,
再去看具体细节实现的时候就很简单了。

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

另外还要注意一点HashMap的链表添加的时候是往链表尾部追加的,但是ConcurrentHashMap中的Segment中的table中链表
在追加新节点HashEntry的时候都是追加在链表的头部,如上图中虚线红色HashEntry所示。

以上就是ConcurrentHashMap在jdk1.7里面的数据架构解读。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值