美文网首页
ConcurrentHashMap

ConcurrentHashMap

作者: 那谁319 | 来源:发表于2019-08-18 21:35 被阅读0次

    sizeCtl:创建ConcurrentHashMap对象时为容器的指定大小处理后的值或者默认值
    sizeCtl:初始化数组时为-1,表示正在初始化

    使用ConcurrentHashMap最长用的也应该是put和get方法

    put方法

    • 1、计算key的hash值
    • 2、如果元素数组为null,未初始化,先初始化数组
    • 3、否则如果通过hash值索引到位置的元素为null,则直接通过CAS操作插入到索引位置,成功直接返回
    • 4、否则如果当前key的hash值索引到的位置的元素的hash值为-1(MOVE,特殊节点),
    • 5、否则,出现了hash冲突,通过链地址法处理hash冲突。

    1、计算hash值

    int hash = spread(key.hashCode());
    
    image.png
    • 获取key的hashcode
    • 高16位和低16位按位异或运算,这样做为了使hash更均匀

    2、初始化数组

    image.png
    • 将sizeCtl的值赋值给sc,并判断sc(即sizeCtl)是否小于0;
    • 如果小于0,当前线程让出CPU,保证只有一个线程能够进行初始化操作
    • 否则如果通过CAS操作将sizeCtl的值设置为-1成功,创建初始化的数组对象,并将当前数组大小的四分之三的值赋值给sizeCtl,(因为n为2的倍数,所以n >>> 2就是n/4,所以 n - (n >>> 2)为n的四分之三)
    • 可以看出初始化数组时,能够进行初始化的线程会将sizeCtl的值通过CAS操作设置为-1

    5、解决hash冲突

    image.png
    • 链表节点(当前Node f的hash值大于0(fh >= 0))

      • 锁住当前头节点,重新获取索引位置的头节点如果等于锁住的节点
      • 如果fh(节点hash值)大于零,遍历头节点关联的链表,找到hash值相同和key相同的节点,直接替换掉老的value即可;当遍历到链表的尾节点时(节点的next指向null),直接修改当前尾节点next指向新添加的几点即可。
    • 树节点(f instanceof TreeBin)

      • 如果当前节点时树节点,走树化解决冲突的逻辑
    • 链表树化

      • 最后根据链表节点的长度是否大于等于8,决定是否将链表存储转化成红黑树存储

    相关文章

      网友评论

          本文标题:ConcurrentHashMap

          本文链接:https://www.haomeiwen.com/subject/hlpwhctx.html