JAVA并发容器源码分析【二】ConcurrentHashMap分析之replaceNode

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

文章首发于:clawhub.club


replaceNode方法

     /**
         * Implementation for the four public remove/replace methods:
         * Replaces node value with v, conditional upon match of cv if
         * non-null.  If resulting value is null, delete.
         * 删除/替换的操作
         *
         */
        final V replaceNode(Object key, V value, Object cv) {
            //发散hash
            int hash = spread(key.hashCode());
            //迭代表
            for (Node<K,V>[] tab = table;;) {
                Node<K,V> f; int n, i, fh;
                //如果表为空,且键所在节点为空,跳出循环
                if (tab == null || (n = tab.length) == 0 ||
                    (f = tabAt(tab, i = (n - 1) & hash)) == null)
                    break;
                //如果key所在节点的hash值为MOVED
                else if ((fh = f.hash) == MOVED)
                    //如果还在进行扩容操作就先进行扩容
                    tab = helpTransfer(tab, f);
                else {
                    V oldVal = null;
                    //是否检验
                    boolean validated = false;
                    //锁当前节点
                    synchronized (f) {
                        //确认节点
                        if (tabAt(tab, i) == f) {
                            //节点的hash值大于0
                            if (fh >= 0) {
                                //校验
                                validated = true;
                                for (Node<K,V> e = f, pred = null;;) {
                                    K ek;
                                    //找到键位置
                                    if (e.hash == hash &&
                                        ((ek = e.key) == key ||
                                         (ek != null && key.equals(ek)))) {
                                        //老的值
                                        V ev = e.val;
                                        //删除节点
                                        if (cv == null || cv == ev ||
                                            (ev != null && cv.equals(ev))) {
                                            oldVal = ev;
                                            if (value != null)
                                                e.val = value;
                                            else if (pred != null)
                                                pred.next = e.next;
                                            else
                                                setTabAt(tab, i, e.next);
                                        }
                                        break;
                                    }
                                    pred = e;
                                    if ((e = e.next) == null)
                                        break;
                                }
                            }
                            //是树形节点
                            else if (f instanceof TreeBin) {
                                validated = true;
                                TreeBin<K,V> t = (TreeBin<K,V>)f;
                                TreeNode<K,V> r, p;
                                //找到删除的key
                                if ((r = t.root) != null &&
                                    (p = r.findTreeNode(hash, key, null)) != null) {
                                    V pv = p.val;
                                    if (cv == null || cv == pv ||
                                        (pv != null && cv.equals(pv))) {
                                        oldVal = pv;
                                        if (value != null)
                                            p.val = value;
                                        //删除树节点
                                        else if (t.removeTreeNode(p))
                                            setTabAt(tab, i, untreeify(t.first));
                                    }
                                }
                            }
                        }
                    }
                    //检查
                    if (validated) {
                        if (oldVal != null) {
                            if (value == null)
                                //数量减一
                                addCount(-1L, -1);
                            return oldVal;
                        }
                        break;
                    }
                }
            }
            return null;
        }

此方法通过以下三处实现多线程的并发访问:

  1. 头节点的synchronized锁。
  2. Node节点的volatile Node<K,V> next属性,用了volatile读。
  3. Node节点的volatile V val属性,用了volatile读。

再盗取一张图:

201910301009\_1.png

remove.png

如图所示:删除的node节点的next依然指着下一个元素。此时若有一个遍历线程正在遍历这个已经删除的节点,这个遍历线程依然可以通过next属性访问下一个元素。从遍历线程的角度看,他并没有感知到此节点已经删除了,这说明了ConcurrentHashMap提供了弱一致性的迭代器。


来源:https://www.jianshu.com/p/a75d196731c0

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » JAVA并发容器源码分析【二】ConcurrentHashMap分析之replaceNode

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏