ConcurrentHashMap常用方法源码解读(一)

  1. 初始化流程
    无参构造就是创建对象,有参构造在创建对象同时对sizeCtl 赋值为比(参数1.5倍加1)大的最小二次幂数。真正创建数组是在第一次put值的时候,创建时将sizeCtl赋值为-1,用来阻止其他线程创建数组,创建完之后再将sizeCtl赋值为0.75倍数组的大小。tableSizeFor的算法可以参考
    大于输入参数且最近的2的整数次幂的数的解析
//构造函数不做事
 public ConcurrentHashMap() {
    }
//有参数的构造函数,将sizeCtl 赋值为比参数的x+x/2+1大的最小二次幂数或者最大容量(参数过大时)
    public ConcurrentHashMap(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException();
        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                   MAXIMUM_CAPACITY :
                   //tableSizeFor取比参数大的最小二次幂数
                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
        this.sizeCtl = cap;
    }


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) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();//第一次赋值时初始化
            ...//略去其他代码


private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        while ((tab = table) == null || tab.length == 0) {
             //初始化过程中将sizeCtl设为-1,这样其他线程进来时自动放弃执行权,当然,sizeCtl用volatile 修饰保证同步,构造时没有传参的话sizeCtl默认为0
            if ((sc = sizeCtl) < 0)
                Thread.yield(); // lost initialization race; just spin
                //SIZECTL表示sizeCtl的内存偏移地址,Unsafe采用CAS算法,当内存中的值与预期值sc相等才将-1写入并返回true,否则返回false,保证线程安全
            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                    if ((tab = table) == null || tab.length == 0) {
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = tab = nt;
                        //将sc赋值成0.75n
                        sc = n - (n >>> 2);
                    }
                } finally {
                    //最终sizeCtl 为旧sizeCtl 的0.75
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }
  1. put(K key, V value)
    用(n - 1) & hash计算数据在数组tab的位置,如果tab[i]为空则不加锁直接往里插值,用CAS保证同步。具体流程见注释
   public V putIfAbsent(K key, V value) {
       //onlyIfAbsent参数为true时表示当不存在值时才插入,存在时就不进行更新
        return putVal(key, value, true);
    }


   public V put(K key, V value) {
        //默认onlyIfAbsent为false
        return putVal(key, value, false);
    }

    /** Implementation for put and putIfAbsent */
    final V putVal(K key, V value, boolean onlyIfAbsent) {
    //ConcurrentHashMap的key不能为空,HashMap可以
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();//初始化
             //tab[i]为空时直接赋值,tabAt相当于获取volatile 修饰的变量
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                //给空的bin赋值没有加锁,一样采用CAS算法,当内存中tab[i]为空时才将新Node写入
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }
            //node的hash等于-1时帮助扩容
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else {
                V oldVal = null;
                //同步锁为Node对象,一个node同一时间只能有一个线程进行以下操作
                synchronized (f) {
                    //上面刚刚赋值,这里重新验证,构成双重验证,如果不相等说明有其他线程改变了f的值,进入下一个循环
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            //本Node链的长度
                            binCount = 1;
                            //循环匹配key值
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
                                //匹配时就赋值
                                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;
                                //没有匹配的key就在node链末尾增加新的node
                                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;
                            //putTreeValkey已存在则返回value,不存在则直接插入并返回null
                            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;
    }
//在TreeNode查找或赋值
final TreeNode<K,V> putTreeVal(int h, K k, V v) {
            Class<?> kc = null;
            boolean searched = false;
            for (TreeNode<K,V> p = root;;) {
                int dir, ph; K pk;
                //p节点为空,则在p节点赋值
                if (p == null) {
                    first = root = new TreeNode<K,V>(h, k, v, null, null);
                    break;
                }
                //比p节点hash值小,则在左边
                else if ((ph = p.hash) > h)
                    dir = -1;
                //比p节点大,则在右边
                else if (ph < h)
                    dir = 1;
                //hash值一致,key与p节点的key一致,就返回p节点
                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                    return p;
                //hash值一致,key与p节点的key不一致,则判断key值是不是可比较的。(comparableClassFor判断k值是不是实现Comparable,不是返回null,简单来说就是判断key是不是字符串或者数字等或其他定义的继承Comparable的可比较的类)不可比较直接从根节点开始搜索
                else if ((kc == null &&
                          (kc = comparableClassFor(k)) == null) ||
                         //如果可比较则先进行比较,如结果为0则从此节点搜索,因此有实现Comparable的key查询效率会更高
                         (dir = compareComparables(kc, k, pk)) == 0) {
                    if (!searched) {
                        TreeNode<K,V> q, ch;
                        //标记是否已查找过,整个循环只查找一次
                        searched = true;
                        if (((ch = p.left) != null &&
                             (q = ch.findTreeNode(h, k, kc)) != null) ||
                            ((ch = p.right) != null &&
                             (q = ch.findTreeNode(h, k, kc)) != null))
                            return q;
                    }
                    //再次对k和pk比较,相等的话dir为-1
                    dir = tieBreakOrder(k, pk);
                }

                TreeNode<K,V> xp = p;
                //按dir的方向走,直到查找到key或者到树的末端
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    TreeNode<K,V> x, f = first;
                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
                    if (f != null)
                        f.prev = x;
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                        //如果父节点不为红色,则该节点为红色
                    if (!xp.red)
                        x.red = true;
                    else {
                    //如果父节点为红色,则要进行染色或旋转平衡处理
                        lockRoot();
                        try {
                            root = balanceInsertion(root, x);
                        } finally {
                            unlockRoot();
                        }
                    }
                    break;
                }
            }
            assert checkInvariants(root);
            return null;
        }
//插入时父节点为红色,进行平衡
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
            //新节点为红色                                        
            x.red = true;
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
                 //没有父节点,说明为根节点,根节点设为黑色
                if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                //父节点为黑色或者祖父节点为空,说明父节点即为跟节点,不做处理
                else if (!xp.red || (xpp = xp.parent) == null)
                    return root;
                //父节点为红色且为祖父节点的左节点
                if (xp == (xppl = xpp.left)) {
                    //伯父节点(祖父节点的右节点)为红,则将祖父节点设为红,父节点和伯父节点设为红,并将x设为祖父节点,进入下一个循环。注意是这里将x的引用替换成祖父节点,并非新节点的位置替换成祖父节点
                    if ((xppr = xpp.right) != null && xppr.red) {
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                    //伯父节点(祖父节点的右节点)为空或为黑,x节点为右节点,则左旋,左旋前将x设为父节点,为下次循环做准备
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        //x节点为左节点,则将父节点染黑,祖父节点弄红再进行右转
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                 //父节点为红色且为祖父节点的右节点,跟上面逻辑反着来,基本一致
                else {
                    //叔叔节点为红,直接染色
                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }
//红黑树左旋
 static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
                                              TreeNode<K,V> p) {
            TreeNode<K,V> r, pp, rl;
            if (p != null && (r = p.right) != null) {
                if ((rl = p.right = r.left) != null)
                    rl.parent = p;
                if ((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                else if (pp.left == p)
                    pp.left = r;
                else
                    pp.right = r;
                r.left = p;
                p.parent = r;
            }
            return root;
        }

你可能感兴趣的:(hashmap,java,数据结构)