JDK并发集合之CocurrentHashMap

一、定义

CocurrentHashMap是线程安全版的HashMap,可以实现线程安全的集合并发操作。在jdk7版本,CocurrentHashMap的底层数据结构是基于数组+链表,且采用分段锁的机制保证线程安全。在jdk8版本,Cocurrent的底层数据结构是基于数组+链表+红黑树,且采用CAS+synchronized的机制来保证线程安全。

二、特性

三、原理

1、保证线程安全的机制

(1)JDK7版本:使用分段锁

CocurrentHashMap会有一个Segment数组,存储Segment元素,每个Segment元素存储若干个HashEntry对象(CocurrentHashMap存储的元素)。其中,每个Segment是一个可重入锁,当出现锁竞争时候,会锁住对应的Segment,从而提高了并发性能。

put方法调用过程(具备线程安全):

(2)JDK8版本:使用CAS+synchronized机制

CocurrentHashMap在进行put操作添加元素时,会先通过CAS机制判断哈希表对应下标的值是否存在,若为空,则使用CAS机制把哈希表对应key的值设置为value;若哈希表对应下标已经有值,则会锁住哈希冲突节点,然后进行添加元素操作,会先判断当前节点是链表节点还是树节点,若是链表节点则会先把该元素放在链表中,然后判断当前链表长度是否大于等于8,是的话会进行树化,在树化过程中,会再判断当前哈希表容量是否大于等于64,是的话,则会把链表转为红黑树,否则,则会调用扩容机制;若是树节点则会通过红黑树的方式加入,该过程和HashMap添加元素的过程一致。

2、添加元素put方法的调用过程(具备线程安全)

  1. put(K key, V value)
    1. putVal(key, value, false)
      1. putVal(K key, V value, boolean onlyIfAbsent)
        1. if (key == null || value == null) throw new NullPointerException();(判断key或value是否为空)
        2. int hash = spread(key.hashCode());
        3. int binCount = 0
        4. for (Node<K,V>[] tab = table;;)(遍历哈希表)
          1. Node<K,V> f; int n, i, fh
          2. if (tab == null || (n = tab.length) == 0)(判断哈希表是否为null或者长度为0)
            1. tab = initTable()(是,进行初始化哈希表)
          3. f = tabAt(tab, i = (n - 1) & hash)(获取哈希表对应下标的元素)
            1. tabAt(Node<K,V>[] tab, int i)
              1. Unsafe getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE)
          4. else if ((f) == null)(判断哈希表对应下标是否有元素)
            1. boolean flag=casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null))(该位置没有元素,则通过CAS方式修改该位置的值为新元素)
              1. casTabAt(Node<K,V>[] tab, int i,Node<K,V> c, Node<K,V> v)
                1. Unsafe compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v)
            2. if (flag)(插入元素成功)
              1. break
          5. else if ((fh = f.hash) == MOVED)(判断是否需要扩容)
            1. tab = helpTransfer(tab, f)
          6. else
            1. V oldVal = null
            2. synchronized (f)(锁住发生哈希冲突的节点)
              1. if (tabAt(tab, i) == f)
                1. if (fh >= 0)(f为链表节点)
                  1.  binCount = 1
                  2. for (Node<K,V> e = f;; ++binCount) 
                    1. K ek
                    2.  if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) 
                      1. oldVal = e.val
                      2. if (!onlyIfAbsent)(判断是否允许覆盖)
                        1.  e.val = value(是,则更新e的值)
                      3. break
                    3. Node<K,V> pred = e
                    4. if ((e = e.next) == null)
                      1. pred.next = new Node<K,V>(hash, key,value, null)
                      2. break
                2. else if (f instanceof TreeBin)(f为树节点)
                  1. Node<K,V> p
                  2. binCount = 2
                  3. if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null)
                    1. oldVal = p.val
                    2. if (!onlyIfAbsent)
                      1. p.val = value
            3. if (binCount != 0) 
              1. if (binCount >= TREEIFY_THRESHOLD)(判断是否需要树化)
                1. treeifyBin(tab, i)
              2. if (oldVal != null)
                1. return oldVal
              3. break
        5. addCount(1L, binCount)
        6. return null
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值