1、HashMap和HashTable的區別
1、HashMap線程不安全,HashTable線程安全
2、因爲線程安全,HashTable效率比HashMap低
3、HashTable的key和value都不能爲空,HashMap只能有一個key爲null,多個value值爲null
4、HashMap默認初始數組大小是16,HashTable默認是11,HashMap擴容2倍,HashTable擴大兩倍+1
5、HashMap需要重新計算hash值,而HashTable直接使用兌現過的hashCode
2、ConcurrentHashMap和HashTable在線程同步上有什麼區別?
HashTable直接使用的synchronized關鍵字
ConcurrentHashMap在jdk7中採用了Segment分段鎖,在jdk8中採用了CAS+synchronized,也採用了分段鎖的方式大大縮小了鎖的粒度,所有ConcurrentHashMap效率比HashTable高
3、hashMap和ConcurrentHashMap的區別
1、ConcurrentHashMap是線程安全的
2、HashMap的key和value都可以爲null,ConcurrentHashMap的key和value都不能爲null
3、紅黑樹相關的節點類,數據結構不同
4、爲什麼 ConcurrentHashMap 比 HashTable 效率要高?
1、HashTable 使用一把鎖(鎖住整個鏈表結構)處理併發問題,多個線程競爭一把鎖,容易阻塞;
2、ConcurrentHashMap 在JDK 1.7 中使用分段鎖(ReentrantLock + Segment + HashEntry),相當於把一個 HashMap 分成多個段,每段分配一把鎖,這樣支持多線程訪問。鎖粒度:基於 Segment,包含多個 HashEntry。
JDK 1.8 中使用 CAS + synchronized + Node + 紅黑樹。鎖粒度:Node(首結點)(實現 Map.Entry<K,V>)。鎖粒度降低了。
5、針對 ConcurrentHashMap 鎖機制具體分析(JDK 1.7 VS JDK 1.8)?
在1.7中,採用分段鎖機制,底層採用數組+鏈表結構
JDK 1.8 中,採用Node + CAS + Synchronized來保證併發安全。取消類 Segment,直接用 table 數組存儲鍵值對;當鏈表長度》=8,鏈表轉換爲紅黑樹,提升性能。底層變更爲數組 + 鏈表 + 紅黑樹。當紅黑樹<=6,降級爲鏈表
6、ConcurrentHashMap 在 JDK 1.8 中,爲什麼要使用內置鎖 synchronized 來代替重入鎖 ReentrantLock?
1、因爲jdk8對synchronized進行了大量優化,效率提升了
2、在大量的數據操作下,對於 JVM 的內存壓力,基於 API 的 ReentrantLock 會開銷更多的內存。
7、ConcurrentHashMap 簡單介紹?
重要的常量:
private transient volatile int sizeCtl;
負數 | 正在初始化或者擴容操作 |
-1 | 正在初始化 |
-N | 代表有N-1個線程正在進行擴容操作 |
0默認值 | 代表還沒有被初始化 |
正數 | 表示初始化大小或者Map中的元素叨叨這個數量是,需要進行擴容了 |
數據結構:
Node 是存儲結構的基本單元,繼承 HashMap 中的 Entry,用於存儲數據;
TreeNode 繼承 Node,但是數據結構換成了二叉樹結構,是紅黑樹的存儲結構,用於紅黑樹中存儲數據;
TreeBin 是封裝 TreeNode 的容器,提供轉換紅黑樹的一些條件和鎖的控制。
存儲對象時(put() 方法):
1.如果沒有初始化,就調用 initTable() 方法來進行初始化;
2.如果沒有 hash 衝突就直接 CAS 無鎖插入;
3.如果需要擴容,就先進行擴容;
4.如果存在 hash 衝突,就加鎖來保證線程安全,兩種情況:一種是鏈表形式就直接遍歷到尾端插入,一種是紅黑樹就按照紅黑樹結構插入;
5.如果該鏈表的數量大於閥值 8,就要先轉換成紅黑樹的結構,break 再一次進入循環
6.如果添加成功就調用 addCount() 方法統計 size,並且檢查是否需要擴容。
擴容方法 transfer():
默認容量爲 16,擴容時,容量變爲原來的兩倍。
獲取對象時(get()方法):
1.計算 hash 值,定位到該 table 索引位置,如果是首結點符合就返回;
2.如果遇到擴容時,會調用標記正在擴容結點 ForwardingNode.find()方法,查找該結點,匹配就返回;
3.以上都不符合的話,就往下遍歷結點,匹配就返回,否則最後就返回 null。
8、ConcurrentHashMap 的併發度是什麼?
1.7中程序運行時能夠同時更新 ConccurentHashMap 且不產生鎖競爭的最大線程數。即Segment數組的長度,默認爲 16,且可以在構造函數中設置。當用戶設置併發度時,ConcurrentHashMap 會使用大於等於該值的最小2冪指數作爲實際併發度(假如用戶設置併發度爲17,實際併發度則爲32)。
1.8中併發度則無太大的實際意義了,主要用處就是當設置的初始容量小於併發度,將初始容量提升至併發度大小。