concurrentHashMap源码解析

Posted 皓洲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了concurrentHashMap源码解析相关的知识,希望对你有一定的参考价值。

concurrentHashMap源码解析

put解析

public V put(K key, V value) {
    return putVal(key, value, false);
}

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
    //判断key和value 不能为null
    if (key == null || value == null) throw new NullPointerException();
    //通过key计算hash值(高16位异或低16位)
    int hash = spread(key.hashCode());
    int binCount = 0;
    //死循环,先获取变量table存在tab中
    for (Node<K,V>[] tab = table;;) {
        //新建一个node节点记为f
        Node<K,V> f; int n, i, fh;
        //如果table为null或者length为0就初始化,初始大小16
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        //i变量标记key所在位置
        //tabAt()返回tab中索引为i的内容,赋值给f判断是否为空
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            //如果是空的就用CAS的原子性操作进行插入
            //操作是:判断table中i位置的值是null,就把新的node节点插入位置i
            if (casTabAt(tab, i, null,
                         new Node<K,V>(hash, key, value, null)))
                break;                   // no lock when adding to empty bin
        }
        //将节点f的hash值赋值给fh,正常情况下hash是>=0的
        //hash为负值的时候有其他意义:表在扩容的时候,老表迁移一个桶需要放一个标记节点(ForingingNode节点)这个Node节点的hash值它固定是-1.
        //MOVED就是-1,这里判断的是f节点是否在进行数据迁移
        else if ((fh = f.hash) == MOVED)
            //执行helpTransfer,顾名思义就是帮助老表进行数据迁移
            //如果这个节点正在进行扩容,那么这个线程就会去获取任务,帮助扩容
            tab = helpTransfer(tab, f);
        else {
            //定义老val并设为空值
            V oldVal = null;
            //对节点f上锁
            synchronized (f) {
                //如果table的i位置还是f的话,这应该是一步保险操作
                if (tabAt(tab, i) == f) {
                    //如果f节点的hash值>=0
                    if (fh >= 0) {
                        binCount = 1;
                        //将节点f赋值给e
                        for (Node<K,V> e = f;; ++binCount) {
                            K ek;
                            //判断e.hash和要插入的hash是否相同,并且判断他们是否为同样的值。
                            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) {
                            oldVal = p.val;
                            if (!onlyIfAbsent)
                                p.val = value;
                        }
                    }
                }
            }
            if (binCount != 0) {
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);
    return null;
}

以上是关于concurrentHashMap源码解析的主要内容,如果未能解决你的问题,请参考以下文章

ConcurrentHashMap源码解析-Java7

ConcurrentHashMap源码解析_04 transfer方法源码分析(难点)

ConcurrentHashMap源码解析_04 transfer方法源码分析(难点)

ConcurrentHashMap源码解析

concurrentHashMap源码解析

concurrentHashMap源码解析