栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

1.8 ConcurrentHashMap 总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

1.8 ConcurrentHashMap 总结

底层结构

Node 数组 + 链表 + 红黑树

原理

synchronized + CAS

构造方法
public ConcurrentHashMap(int initialCapacity) {  
    if (initialCapacity < 0) 
        throw new IllegalArgumentException();   
    int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
            MAXIMUM_CAPACITY :              
            tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));  
    this.sizeCtl = cap;
}

public ConcurrentHashMap(int initialCapacity, float loadFactor) {
    this(initialCapacity, loadFactor, 1);
}

public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
    if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)   
        throw new IllegalArgumentException();   
    if (initialCapacity < concurrencyLevel)   // Use at least as many bins     
        initialCapacity = concurrencyLevel;   // as estimated threads   
    long size = (long)(1.0 + (long)initialCapacity / loadFactor);
    int cap = (size >= (long)MAXIMUM_CAPACITY) ?    
        MAXIMUM_CAPACITY : tableSizeFor((int)size);
    this.sizeCtl = cap;
}
put 方法
  • key 和 value 不能为 null,否则抛出空指针异常
  • 计算 hash 值:key.hashCode() 高 16 位与低 16 位异或后将最高位(符号位)置 0,保证其非负,因为 hash 值为负数时有特殊含义:
    static final int MOVED     = -1; // hash for forwarding nodes
    static final int TREEBIN    = -2; // hash for roots of trees
    static final int RESERVED  = -3; // hash for transient reservations
    
  • 判断数组是否已初始化,若未初始化则调用 initTable() 方法进行初始化,使用了 CAS 操作
  • 找到下标处的元素 (下标计算方式为 hash & length - 1)
  • 如果下标位置的元素为 null 则直接插入 (CAS)
  • 若正在扩容则帮助扩容
  • synchronized 锁住下标处的元素
    • 链表:使用尾插法插入新节点,若插入后链表长度超过 8 且数组长度 >= 64 则进行转红黑树(第二个条件不满足则进行扩容)
    • 红黑树:调用 putTreeVal 方法将节点插入到红黑树中
  • 调用 addCount 方法,计数并判断是否需要扩容 (扩容条件好像比 元素数量(插入后) > 容量 * 加载因子(默认0.75) 还要强一点,fullAddCount 后直接 return 了,暂时还没弄清楚);baceCount 和 counterCells 共同计数,获取元素个数时需要将 baseCount 和 counterCells 中各个位置的 value 加起来
扩容
  • 若其他线程已经在扩容了则帮助扩容
  • 数据迁移过程
    • synchronized 锁住下标处的元素
      • 链表:找到最后一段新下标相同的小链表,遍历其他元素,按新下标位置构造两条链表 (头插法),然后一次性移过去 (效果与 1.7 相同),最后把老数组上该位置的元素设置为 ForwardingNode 对象
      • 红黑树:按新下标构造两条双向链表,若链表长度小于等于 6 则将该链表的节点类型 (TreeNode) 转换为普通链表节点,若链表长度大于 6,如果另一条链表不为空则需要重新树化 (另一条链表为空则就是原来那棵树整个移过去)
链表转红黑树

与 HashMap 类似,不过数组元素的类型是 TreeBin 而不是 TreeNode,树的根节点作为 TreeBin 的属性,这样根节点的改变就不会对锁造成影响了,因为锁的是 TreeBin 对象

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/937418.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号