1. 程式人生 > >小議 JDK 1.8 中的 ConCurrentHashMap 和 ConcurrentSkipListMap

小議 JDK 1.8 中的 ConCurrentHashMap 和 ConcurrentSkipListMap

A)  ConCurrentHashMap 在 jdk1.8 中主要做了兩方面的改進。

1) 取消segments欄位,直接採用transient volatile HashEntry<K,V>[] table儲存資料,

     採用table陣列元素作為鎖,從而實現了對每一行資料進行加鎖,進一步減少併發衝突的概率。

2) 把Table陣列+單向連結串列的資料結構   變成為  Table陣列 + 單向連結串列 + 紅黑樹的結構。

     注: 當連結串列長度超過8以後,單向連結串列變成了紅黑數;  在雜湊表擴容時,如果發現連結串列長度小於 6,則會由紅黑樹重新退化為連結串列。

      對於hash表來說,最核心的能力在於將key hash之後能均勻的分佈在陣列中。如果hash之後雜湊的很均勻,那麼table陣列中的每個佇列長度主要為0或者1。但實際情況並非總是如此理想,雖然ConcurrentHashMap類預設的載入因子為0.75,但是在資料量過大或者運氣不佳的情況下,還是會存在一些佇列長度過長的情況,如果還是採用單向列表方式,那麼查詢某個節點的時間複雜度為O(n);   因此,對於個數超過8(預設值)的列表,jdk1.8中採用了紅黑樹的結構,那麼查詢的時間複雜度可以降低到O(logN),可以改進效能。

  3) ConcurrentHashMap jdk1.7、jdk1.8效能比較,結果如下:

 

  

 

 B) ConcurrentSkipListMap與非阻塞佇列ConcurrentBlockingQueue的原理一樣。

       ConcurrentSkipListMap提供了一種執行緒安全的併發訪問的排序對映表。內部是SkipList(跳錶)結構實現,利用底層的插入、刪除的CAS原子性操作,通過死迴圈不斷獲取最新的結點指標來保證不會出現競態條件。在理論上能夠在O(log(n))時間內完成查詢、插入、刪除操作。呼叫ConcurrentSkipListMap的size時,由於多個執行緒可以同時對對映表進行操作,所以對映表需要遍歷整個連結串列才能返回元素個數,這個操作是個O(log(n))的操作。

  在JDK1.8中,ConcurrentHashMap的效能和儲存空間要優於ConcurrentSkipListMap,但是ConcurrentSkipListMap有一個功能: 它會按照鍵的自然順序進行排序。

故需要對鍵值排序,則我們可以使用TreeMap,在併發場景下可以使用ConcurrentSkipListMap