美文网首页JAVA进阶
对ConcurrentHashMap源码#get方法走读笔记及心

对ConcurrentHashMap源码#get方法走读笔记及心

作者: i_cyy | 来源:发表于2019-07-06 22:03 被阅读0次
    /*
     * 源码中没有一处加锁,却能保证线程安全,Node的成员val是用volatile修饰,保证了线程间的可见性。
     * 成员val是用volatile修饰和数组用volatile修饰没有关系,数组用volatile修饰主要是保证在数组扩容的时候保证可见性。
     */
    public V get(Object key) {
            Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek; //大佬们写代码都是在使用的时候才初始化,非常优雅
            int h = spread(key.hashCode()); //计算hash
            if ((tab = table) != null && (n = tab.length) > 0 &&
                (e = tabAt(tab, (n - 1) & h)) != null) { //读取首节点的Node元素
                if ((eh = e.hash) == h) { //如果该节点就是首节点就返回
                    if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                        return e.val;
                }
                //hash值为负值表示正在扩容,这个时候查的是ForwardingNode的find方法来定位到nextTable来
                //eh=-1,说明该节点是一个ForwardingNode,正在迁移,此时调用ForwardingNode的find方法去nextTable里找。
                //eh=-2,说明该节点是一个TreeBin,此时调用TreeBin的find方法遍历红黑树,由于红黑树有可能正在旋转变色,所以find里会有读写锁。
                //eh>=0,说明该节点下挂的是一个链表,直接遍历该链表即可。
                else if (eh < 0)
                    return (p = e.find(h, key)) != null ? p.val : null;
                while ((e = e.next) != null) { //既不是首节点也不是ForwardingNode,那就往下遍历
                    if (e.hash == h &&
                        ((ek = e.key) == key || (ek != null && key.equals(ek))))
                        return e.val;
                }
            }
            return null;
    }
    

    读完 ConcurrentHashMap 源码#get方法,才发现,多线程并发读下保证线程安全的思路,不仅仅是加锁才能完成,完全可以不加锁也做到,就是合理的运用 volatile 关键字,去保证所要读的变量线程间的可见性,也是无锁编程的一个思想。

    相关文章

      网友评论

        本文标题:对ConcurrentHashMap源码#get方法走读笔记及心

        本文链接:https://www.haomeiwen.com/subject/qbgmhctx.html