美文网首页
Java 1.8 Concurrent HashMap 数据结构

Java 1.8 Concurrent HashMap 数据结构

作者: 攻城狮托马斯 | 来源:发表于2020-05-17 14:44 被阅读0次

    在Concurrent1.8中, 取消了segment, 直接对Table[]加锁(换了名字, 几乎是1.7中的hashEntry). 当node数量大于8的时候, 转为红黑树, 而当红黑树数量小于6的时候, 转回链表.

    核心数据结构

    在Node中, 拥有value和next,都是volatile,可以看见最新的值. 还有两个数据结构

    TreeNode 和 TreeNodeBin

    TreeNode extends Node

    TreeNodebin(红黑树的容器, 包含红黑树的根节点, 还有指针来确立是否为读写锁)

    ForwardingNode(在扩容的时候使用, 先放到要扩容的地点)

    private transient volatile int sizeCtl;

    当为负数时,-1 表示正在初始化,-N 表示 N - 1 个线程正在进行扩容;

    当为 0 时,表示 table 还没有初始化;

    当为其他正数时,表示初始化或者下一次进行扩容的大小。

    核心方法

    tabAt(), casTabAt(), setTabAt(), native级方法来保证数据的有效性.

    intiliaze(): 不会initiliaze()某个node, 而是大致地initialize HashMap设置参数, 并没有在内存中加入object, 而真正对table进行初始化则是在每一个put()操作中, 查看是否会初始化.

    get():找到是哪个tab(node), 然后根据红黑树还是链表进行查找.

    如果遇到扩容时,会调用标记正在扩容结点 ForwardingNode.find()方法, 查找该结点,匹配就返回

    putVal(): 

    1.检查tab是不是空的, 初始化tab, 用CAS的方法初始化tab, 如果失败,  让出CPU执行权.

    2.检查是否在扩容,如果在扩容,线程帮助扩容。

    3.如果没有头部节点, 则通过CAS添加头部节点.

    4.如果都不是,synchronize锁住table节点(头部节点),尾插法,插在链表或者树的尾端. 

    remove(): 找到tab,检查是否需要红黑树转链表. 

    transfer()(扩容): 建立一个新的table, 遍历表中的每个node通过rehash复制到新表中.

    对每一个node进行重新hash值,并且是并发扩容, 每一个线程只做一个范围内的节点, 做好之后变成forwardingNode. 更新sizeCtl为新容量的0.75倍数. 

    size(): 在remove和put()中对size进行实时更新, 调用addCount()计算方法, 通过CAS的方法更新.(//sumCount()才是真正实现方法, 但是具体有两个参数和CAS操作, 就算写了也记不起来, 就按上面的来记)

    相关文章

      网友评论

          本文标题:Java 1.8 Concurrent HashMap 数据结构

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