01.02 ConcurrentHashMap面試總結

ConcurrentHashMap和hashtabie的區別

ConcurrentHashMap 和 Hashtable 的區別主要體現在實現線程安全的方式上不同。

底層數據結構: JDK1.7的 ConcurrentHashMap 底層採用 分段的數組+鏈表實現,JDK1.8 採用的數據結構跟HashMap1.8的結構一樣,數組+鏈表/紅黑二叉樹。Hashtable 和 JDK1.8 之前的HashMap 的底層數據結構類似都是採用數組+鏈表的形式,數組是 HashMap 的主體,鏈表則是主要為了解決哈希衝突而存在的;

實現線程安全的方式(重要): ① 在在JDK1.7的時候,ConcurrentHashMap(分段鎖)對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器裡不同數據段的數據,就不會存在鎖競爭,提高併發訪問率。 到了到了 JDK1.8 的時候已經摒棄了Segment的概念,而是直接用的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,併發控制使用紅黑樹的數據結構來實現,併發控制使用

synchronized 和和 CAS 來操作。(JDK1.6以後對 synchronized鎖做了很多優化) 整個看起來就像是優化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數據結構,但是已經簡化了屬性,只是為了兼容舊版本;② Hashtable(同一把鎖) :使用 ynchronized 來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另一個線程不能使用 put 添加元素,也不能使用 get,競爭會越來越激烈效率越低。

兩者的對比圖:

圖片來源:http://www.cnblogs.com/chengxiao/p/6842045.html

HashTable:


ConcurrentHashMap面試總結

JDK1.7的ConcurrentHashMap:


ConcurrentHashMap面試總結

JDK1.8的ConcurrentHashMap(TreeBin: 紅黑二叉樹節點Node: 鏈表節點):


ConcurrentHashMap面試總結

ConcurrentHashMap線程安全的具體實現方式/底層具體實現

JDK1.7(上面有示意圖)

首先將數據分為一段一段的存儲,然後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據時,其他段的數據也能被其他線程訪問。

ConcurrentHashMap 是由是由 Segment 數組結構和 HashEntry 數組結構組成。

Segment 實現了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用於存儲鍵值對數據。

<code>static class Segment extends ReentrantLock implements Serializable {/<code>
<code>}/<code>

一個 ConcurrentHashMap 裡包含一個 Segment 數組。Segment 的結構和HashMap類似,是一種數組和鏈表結構,一個 Segment 包含一個 HashEntry 數組,每個 HashEntry 是一個鏈表結構的元素,每個 Segment 守護著一個HashEntry數組裡的元素,當對 HashEntry 數組的數據進行修改時,必須首先獲得對應的 Segment的鎖。

JDK1.8(上面有示意圖)

ConcurrentHashMap取消了Segment分段鎖,採用CAS和synchronized來保證併發安全。數據結構跟

HashMap1.8的結構類似,數組+鏈表/紅黑二叉樹。Java 8在鏈表長度超過一定閾值(8)時將鏈表(尋址時間複雜度為O(N))轉換為紅黑樹(尋址時間複雜度為O(long(N)))

synchronized只鎖定當前鏈表或紅黑二叉樹的首節點,這樣只要hash不衝突,就不會產生併發,效率又提升N倍。


分享到:


相關文章: