對ConcurrentHashMap源碼#get方法走讀筆記及心得

/*
 * 源碼中沒有一處加鎖,卻能保證線程安全,Node的成員val是用volatile修飾,保證了線程間的可見性。
 * 成員val是用volatile修飾和數(shù)組用volatile修飾沒有關(guān)系,數(shù)組用volatile修飾主要是保證在數(shù)組擴(kuò)容的時(shí)候保證可見性。
 */
public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek; //大佬們寫代碼都是在使用的時(shí)候才初始化,非常優(yōu)雅
        int h = spread(key.hashCode()); //計(jì)算hash
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) { //讀取首節(jié)點(diǎn)的Node元素
            if ((eh = e.hash) == h) { //如果該節(jié)點(diǎn)就是首節(jié)點(diǎn)就返回
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }
            //hash值為負(fù)值表示正在擴(kuò)容,這個(gè)時(shí)候查的是ForwardingNode的find方法來定位到nextTable來
            //eh=-1,說明該節(jié)點(diǎn)是一個(gè)ForwardingNode,正在遷移,此時(shí)調(diào)用ForwardingNode的find方法去nextTable里找。
            //eh=-2,說明該節(jié)點(diǎn)是一個(gè)TreeBin,此時(shí)調(diào)用TreeBin的find方法遍歷紅黑樹,由于紅黑樹有可能正在旋轉(zhuǎn)變色,所以find里會(huì)有讀寫鎖。
            //eh>=0,說明該節(jié)點(diǎn)下掛的是一個(gè)鏈表,直接遍歷該鏈表即可。
            else if (eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) { //既不是首節(jié)點(diǎn)也不是ForwardingNode,那就往下遍歷
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
}

讀完 ConcurrentHashMap 源碼#get方法,才發(fā)現(xiàn),多線程并發(fā)讀下保證線程安全的思路,不僅僅是加鎖才能完成,完全可以不加鎖也做到,就是合理的運(yùn)用 volatile 關(guān)鍵字,去保證所要讀的變量線程間的可見性,也是無鎖編程的一個(gè)思想。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容