• ConcurrentHashMap transfer 方法的一点说明


    最近在找工作,也在夯实基础。今天差不多读了一整天的 并发map,特记录一点收获。

    如何保证在并发情况下resize扩容时的安全性。

    1、两个数组变量,均是成员变量(table nextTable),迁移时是以桶为单位,且会用synchronized锁住桶。只要桶迁移完了,会先将生成的新的数组放置到新数组上,那在旧数组对应的位置,cas将元素设置成 ForwardingNode(请注意该特殊节点的构造方法)。

                                setTabAt(nextTab, i, ln);

                                setTabAt(nextTab, i + n, hn);

                                setTabAt(tab, i, fwd);

        static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {

            U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);

        }

    2、当在扩容时,有多个线程前来操作map时

    2.1、若是put或者remove,则需要定位到对应的桶上且锁住。

    2.1.1 如果当前桶正在扩容中进行迁移,那么将无法获取到锁,许等待这个桶处理完毕。

    2.1.2 如果获取到锁,则会判断获取锁前后的桶是否一致,只有一致时才会进行put和remove操作

    2.1.3 如果当前桶为 ForwardingNode 节点,则表示当前桶的数据已被迁移到新数据,进入 helpTransfer 方法

    2.2、进入协助扩容

    2.2.1 成功协助扩容,则会将负责的分配给自己的桶迁移完毕。若本线程负责的桶处理完毕,但是其他线程负责的桶未处理完毕,看代码应该是空转cpu(此处逻辑可能没有理清)。

    2.2.2 若不需要协助,则会直接返回ForwardingNode节点下 nextTab,去追溯构造方法会发现 nextTab 引用的实例变量 nextTable。然后就在新的数组上直接操作remove或者put。

    2.3、若在此时获取指定是值

    2.3.1 在旧数组上判断桶是否存在,存在且不是链表,则直接返回数据

    2.3.2 旧数组上存在且为 ForwardingNode ,则调用 ForwardingNode.find 方法去新数组上查找数据

  • 相关阅读:
    使用InstelliJ IDEA创建Web应用程序
    别了WindowsXP
    在MyEclipse中搭建Spring MVC开发环境
    iPhone中国移动收不到彩信,联通不用设置都可以,具体设置方法:
    WebLogic 服务器配置
    c# 第五课 string
    c# 第五课 regex
    c# 第四课 Arrays
    c# 第四课 interfaces
    c# 第五课 async await
  • 原文地址:https://www.cnblogs.com/brave-rocker/p/13338299.html
Copyright © 2020-2023  润新知