輕鬆理解ConcurrentHashMap的原理

2021-10-05 05:23:47 字數 2772 閱讀 1813

concurrenthashmap是一種執行緒安全的hashmap,相對於hashtable, 它擁有更高的併發性.

現在,我們就來分析一下在jdk1.8下的concurrenthashmap的實現及原理:

public v get(object key) 

//hash值為負值表示正在擴容,這個時候查的是forwardingnode的find方法來定位到nexttable來

//eh=-1,說明該節點是乙個forwardingnode,正在遷移,此時呼叫forwardingnode的find方法去nexttable裡找。

//eh=-2,說明該節點是乙個treebin,此時呼叫treebin的find方法遍歷紅黑樹,由於紅黑樹有可能正在旋轉變色,所以find裡會有讀寫鎖。

else if (eh < 0)

//eh>=0,說明該節點下掛的是乙個鍊錶,直接遍歷該鍊錶即可。

while ((e = e.next) != null)

}return null;//未找到對應的值

}

可以看到,在1.8中concurrenthashmap的get操作全程不需要加鎖,這也是它比其他併發集合比如hashtable、用collections.synchronizedmap()包裝的hashmap;安全效率高的原因之一。

concurrenthashmap的get操作為什麼不需要加鎖呢?

大家都知道,執行緒安全常常是因為獲取的共享變數不一致而導致的,而get方法中訪問到的共享變數只有node型別的陣列table,

transient volatile node table;
而volatile關鍵字可以保證共享變數的可見性, 即實時訪問到其他執行緒修改後的資料. 那麼,get方法不加鎖的原因是因為table變數使用了volatile修飾麼, 其實不然, volatile關鍵字對於基本型別的修改可以在隨後對多個執行緒的讀保持一致, 但是對於引用型別如陣列,實體bean,僅僅保證引用的可見性,但並不保證引用內容的可見性

真正的原因是因為在node類中val變數和next變數是用volatile修飾了, 也是因為此處保證了concurrenthashmap的get方法的執行緒安全

static class nodeimplements map.entry
由以上可以看出

get操作全程不需要加鎖是因為node的成員val是用volatile修飾的陣列用volatile修飾沒有關係

陣列用volatile修飾主要是保證在陣列擴容的時候保證可見性。

那麼, node陣列table為什麼要用volatile修飾呢?

其實就是為了使得node陣列在擴容的時候對其他執行緒具有可見性而加的volatile

final v putval(k key, v value, boolean onlyifabsent) 

//hash桶(tab[i])是fwd節點,表示正在擴容

else if ((fh = f.hash) == moved)

//擴容

tab = helptransfer(tab, f);

else

nodepred = e;

//遍歷鍊錶,向尾結點插入資料

if ((e = e.next) == null) }}

//紅黑樹

else if (f instanceof treebin) }}

}if (bincount != 0) }}

//雜湊桶儲存的元素個數+1

addcount(1l, bincount);

return null;

}

從原始碼中看出,put方法在往空的雜湊桶新增元素時,是採用cas演算法無鎖插入的; 只有在發生雜湊碰撞時,才會給雜湊桶加上鎖,鎖是每個雜湊桶的頭結點.

public v remove(object key) 

/*** 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.

* * 四個公共刪除/替換方法的實現:用v替換節點值,條件是如果非空則匹配cv。如果結果值為null,請刪除。

* */

final v replacenode(object key, v value, object cv)

break;

}pred = e;

if ((e = e.next) == null)

break;}}

//紅黑樹

else if (f instanceof treebin) }}

}}if (validated)

break;}}

}return null;

}

remove方法也是鎖住雜湊桶的頭結點.依賴於cas算

輕鬆理解EJB

昨天給乙個班講jsp,那個班已經把所有的技術都學完了,但是學的不好,那個學校讓我過去快速的重講一遍,真的很累,這些學生也很令人感到,他們除了聽我的課,還插班聽其他老師的課,上午我聽說他們剛剛聽別的老師講ejb很暈,我決定臨時調整授課內容,給他們講清楚ejb。ejb難點在多個檔案,他們的作用是什麼?如...

輕鬆理解 Fisher判別

以前看費舍爾判別,老是看一點就看不下去,今天耐著性子看完後,發現這個東西真的是很神奇,而且是線性判別,最後只要計算乙個向量乘法和減法,然後比較最小值就能解決判別問題,下面用例子講比較好理解,我們來判斷乙個東西是人,猴,豬,狗?四個總體,可以包含幾個分量,比如重量,身高,智商,情商這四個分量,所以現在...

輕鬆理解KMP演算法

字串匹配 是計算機的基本任務之一。舉例來說,有乙個字串 bbc abcdab abcdabcdabde 我想知道,裡面是否包含另乙個字串 abcdabd 許多演算法可以完成這個任務,knuth morris pratt演算法 簡稱kmp 是最常用的之一。它以三個發明者命名,起頭的那個k就是著名科學家...