Concurrenthashmap

类的继承关系
Concurrenthashmap继承自Abstractmap实现了map,cloneable,serillizable接口
成员变量
//最大容量
private static final int MAXIMUM_CAPACITY = 1 << 30;
//默认容量 16
private static final int DEFAULT_CAPACITY = 16;
//加载因子
private static final float LOAD_FACTOR = 0.75f;
//转为红黑树判断条件之一 bin数量大于8
static final int TREEIFY_THRESHOLD = 8;
//由树转换成链表的阈值当执行resize操作时
//当桶中bin的数量少于时使用链表来代替树。默认值是6
static final int UNTREEIFY_THRESHOLD = 6;
//如果bin中的数量大于TREEIFY_THRESHOLD,但是capacity小于MIN_TREEIFY_CAPACITY,依然使用链表存储。
此时会进行resize操作,如果capacity大于MIN_TREEIFY_CAPACITY进行树化
static final int MIN_TREEIFY_CAPACITY = 64;
//扩容线程每次最少要迁移16个hash桶
private static final int MIN_TRANSFER_STRIDE = 16;
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
//当前位置的Node是一个ForwardingNode节点
static final int MOVED = -1;
//当前位置的Node为一个TreeBin节点
static final int TREEBIN = -2;
//暂存态,即这个节点没有真正初始化完毕
static final int RESERVED = -3;
static final int HASH_BITS = 0x7fffffff;
/** 可用处理器(cpu)数量 */
static final int NCPU=Runtime.getRuntime().availableProcessors();
//桶数组,用来存储Node元素的。默认为null,只在第一次put操作的进行初始化,该数组的长度永远为2的n次方。
transient volatile Node<K,V>[] table;
//默认为null,当不为null,表示当前正在进行扩容操作,这个数组就是扩容之后的数组,长度为原数组的两倍。
private transient volatile Node<K,V>[] nextTable;
//map中元素个数,由于是多线程操作,baseCount记录的不准确,所以要结合counterCells 来使用保证记录的正确性。map的元素个数 = baseCount + 所有的cell的value值。
private transient volatile long baseCount;

  • 表初始化和扩容的控制位。
  • -1表示当前table数组正在被初始化;
  • -N表示有N-1个线程在进行扩容操作;
  • 0(默认值)表示当前table还未使用;此时table为null;
  • 正整数时,表示table的容量,默认是table大小的0.75倍,(n - (n>>>2))的方式来计算0.75
    private transient volatile int sizeCtl;
    //用户拆分table的,在扩容的时候
    private transient volatile int transferIndex;
    // 用来实现cellsBusy锁的,0无锁,1锁;添加map大小使用
    private transient volatile int cellsBusy;
    // 用来避免伪共享 counterCells用来记录size大小
    private transient volatile CounterCell[] counterCells;
    3)构造函数
    initTable()解析
    put()解析
    addCount()解析
    解析transfer()
    解析get()方法
    4) put方法分析
    public V put(K key, V value) {
    return putVal(key, value, false);
    }
    final V putVal(K key, V value, boolean onlyIfAbsent) {
    //检验key,value不能为空
    if (key == null || value == null) throw new NullPointerException();
    //计算hash值。高16位异或低16位与HASH_BITS
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<K,V>[] tab = table;😉 {
    Node<K,V> f; int n, i, fh;
    //如果node数组为空,则初始化table
    if (tab == null || (n = tab.length) == 0)
    tab = initTable();
    //返回(n - 1) & hash=index 位置的元素
    else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
    //通过cas赋值。
    if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))
    //这里操作不需要锁,即使multi thread add 那么只会有一个执行成功。casTabAt是原子操作
    break;
    }
    //f.hash == MOVED表示当前数组正在扩容。则进行帮助扩容
    else if ((fh = f.hash) == MOVED)
    tab = helpTransfer(tab, f);
    else {
    V oldVal = null;
    //注意,这里针对数组的某一个桶加锁
    synchronized (f) {
    //校验f
    if (tabAt(tab, i) == f) {
    //fh >= 0得到的节点就是hash值相同的节点组成的链表的头节点
    if (fh >= 0) {
    binCount = 1;
    //遍历数组
    for (Node<K,V> e = f;; ++binCount) {
    K ek;
    //根据hash找到key,判断是否可以覆盖原来的值
    //onlyIfAbsent=false覆盖
    if (e.hash == hash &&
    ((ek = e.key) == key ||
    (ek != null && key.equals(ek)))) {
    oldVal = e.val;
    if (!onlyIfAbsent)
    e.val = value;
    break;
    }
    Node<K,V> pred = e;
    if ((e = e.next) == null) {
    //说明遍历到链表的尾节点还没找到元素,直接构建元素,跟链表连接上
    pred.next = new Node<K,V>(hash, key, value, null);
    break;
    }
    }
    }
    //说明链表是红黑树
    else if (f instanceof TreeBin) {
    Node<K,V> p;
    binCount = 2;
    //把当前元素加入树
    if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {
    //根据onlyIfAbsent判断是否覆盖
    oldVal = p.val;
    if (!onlyIfAbsent)
    p.val = value;
    }
    }
    }
    }
    if (binCount != 0) {
    //binCount >= TREEIFY_THRESHOLD说明要把链表转为红黑树
    if (binCount >= TREEIFY_THRESHOLD)
    //链表转树
    treeifyBin(tab, i);
    //老值不为空,返回原来的值
    if (oldVal != null)
    return oldVal;
    break;
    }
    }
    }
    //map的容量加1,检查map是否需要扩容
    addCount(1L, binCount);
    return null;
    }
    //计算hash值
    static final int spread(int h) {
    return (h ^ (h >>> 16)) & HASH_BITS;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_43895388

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值