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源码解析

concurrentHashMap源码解析

concurrentHashMap源码解析

concurrentHashMap源码解析

ConcurrentHashMap -1.8 源码解析