我是靠谱客的博主 瘦瘦毛豆,最近开发中收集的这篇文章主要介绍ConcurrentHashMap源码分析(二) ---- get方法和remove方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

有了前文的基础,直接看到get方法

    public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
        //计算hash值
        int h = spread(key.hashCode());
        //如果table初始化过 且 根据hash定位到对应位置的table上有数据
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) {
            //判断头部数据的hash 和 key 和传入的数据是否一致
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                	//一致直接返回该值
                    return e.val;
            }
            //如果是树节点,或者该节点已经被迁移到新的table上 这里只看ForwardingNode的find方法,不看树的相关操作了
            else if (eh < 0)
            	//看到find方法
                return (p = e.find(h, key)) != null ? p.val : null;
            //遍历链表寻找对应的数据
            while ((e = e.next) != null) {
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        //找不到,返回null
        return null;
    }

ForwardingNode的find方法

	static final class ForwardingNode<K,V> extends Node<K,V> {
        final Node<K,V>[] nextTable;
        ForwardingNode(Node<K,V>[] tab) {
            super(MOVED, null, null, null);
            this.nextTable = tab;
        }
		
        Node<K,V> find(int h, Object k) {
            // loop to avoid arbitrarily deep recursion on forwarding nodes
            //从新的table上查找数据
            outer: for (Node<K,V>[] tab = nextTable;;) {
                Node<K,V> e; int n;
                //如果新的table的对应位置上的节点为空,直接返回空
                if (k == null || tab == null || (n = tab.length) == 0 ||
                    (e = tabAt(tab, (n - 1) & h)) == null)
                    return null;
                //该位置上有值,在该位置查找数据    
                for (;;) {
                    int eh; K ek;
                    //如果头节点符合要求,直接返回头节点
                    if ((eh = e.hash) == h &&
                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                    //如果是树节点,或者该节点已经被迁移到新的table上 
                    if (eh < 0) {
                        if (e instanceof ForwardingNode) {
                        	//获取到新的table,重新循环查找
                            tab = ((ForwardingNode<K,V>)e).nextTable;
                            continue outer;
                        }
                        //从树中查找节点
                        else
                            return e.find(h, k);
                    }
                    //如果下一个节点为空,直接返回空
                    //否则,接着判断下一个节点是否满足条件
                    if ((e = e.next) == null)
                        return null;
                }
            }
        }
    }

再来看到remove方法

	public V remove(Object key) {
		//调用的replaceNode方法,后两个参数为空
        return replaceNode(key, null, null);
    }
    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;
            //table 还未初始化, 或者table对应位置(i)上没有数据 ,直接break
            if (tab == null || (n = tab.length) == 0 ||
                (f = tabAt(tab, i = (n - 1) & hash)) == null)
                break;
            //如果该节点已经被迁移到新的table上,则尝试帮助迁移
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else {
                V oldVal = null;
                boolean validated = false;
                //锁住table对应位置的头节点
                synchronized (f) {
                	//获取到i位置的头节点,如果没有发生改变
                    if (tabAt(tab, i) == f) {
                    	//从链表上找
                        if (fh >= 0) {
                        	//validated 修改为true
                            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)))) {
                                    //获取节点的value为 ev
                                    V ev = e.val;
                                    //入参cv为空 或者 ev和cv 或者 节点的值不为空 或者cv equals ev
                                    if (cv == null || cv == ev ||
                                        (ev != null && cv.equals(ev))) {
                                        //oldVal保存ev的值
                                        oldVal = ev;
                                        //入参的value不为空
                                        if (value != null)
                                            //将该节点的value替换为入参的value
                                            e.val = value;
                                        //如果有前一个节点(不是头节点)
                                        else if (pred != null)
                                        	//将当前节点从链表中断开
                                            pred.next = e.next;
                                        //如果是头节点,直接将头节点设置为下一个节点
                                        else
                                            setTabAt(tab, i, e.next);
                                    }
                                    //跳出循环
                                    break;
                                }
                                //pred记录前一个节点
                                pred = e;
                                //e修改为下一个节点,下一个节点为空,则break循环结束
                                if ((e = e.next) == null)
                                    break;
                            }
                        }
                        //从树中找
                        else if (f instanceof TreeBin) {
                        	//validated 修改为true
                            validated = true;
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            TreeNode<K,V> r, p;
                            //从树中查找节点
                            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;
                                    //从树中删除节点,返回true说明树中节点数过少
                                    else if (t.removeTreeNode(p))
                                    	//降级为链表,设置回table中
                                        setTabAt(tab, i, untreeify(t.first));
                                }
                            }
                        }
                    }
                }
                //如果validated为true
                if (validated) {
                	//如果oldVal 不为空,返回oldVal 
                    if (oldVal != null) {
                        if (value == null)
                        	//对baseCount或者counterCell的值减一
                            addCount(-1L, -1);
                        return oldVal;
                    }
                    break;
                }
            }
        }
        return null;
    }    

最后

以上就是瘦瘦毛豆为你收集整理的ConcurrentHashMap源码分析(二) ---- get方法和remove方法的全部内容,希望文章能够帮你解决ConcurrentHashMap源码分析(二) ---- get方法和remove方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(238)

评论列表共有 0 条评论

立即
投稿
返回
顶部