ConcurrentHshMap利用CAS+Synchronized來保證并發(fā)更新安全潜沦,底層依然使用數(shù)組+鏈表+紅黑樹的存儲結構
主要屬性
table : 默認為NULL睛廊,初始化發(fā)生在第一次插入操作,默認大小為16的數(shù)組态鳖,用來儲存Node節(jié)點數(shù)據(jù)簇爆,擴容時大小總是2的冪次方。
nextTable:默認為NULL峦嗤,擴容時新生成的數(shù)組,大小為原數(shù)組的兩倍滚粟。
sizeCtl (控制標識符):默認為0寻仗,用來控制table的初始化和擴容操作
* ?-1 代表table正在初始化
* ?-N 正有N-1個線程正在進行擴容操作
* ?N 下一次需要擴容的臨界值,與HashMap中的臨界值一樣
Node節(jié)點類
final int hash凡壤;
final K key署尤;
volatile V val; ? ? 用volatile修飾的value和next 保證了并發(fā)內存的可見性?
volatile Node<K,V> next;
ForwardingNode?
final Node<K,V> [] nextTable;
super (-1,NULL,NULL,NULL,NULL) hash值為-1其它為NULL
// ForwardingNode 只在擴容是發(fā)揮作用亚侠,負責表示當前節(jié)點以被copy走了曹体。
put方法
計算key的hashcode在hash得出index數(shù)組中存放的位置
檢查數(shù)組是否初始化若未初始化則進行初始化
1若table[index]==null ,該節(jié)點為空 ,利用CAS操作插入數(shù)據(jù)
2若table[index]!=null ,該位置已有節(jié)點硝烂,發(fā)生碰撞 ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?a . 檢查該節(jié)點的hash值是否為-1 箕别,若為-1則說明有線程正在進行擴容操作 ,調用helpTransfer幫助其擴容
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?b . 該節(jié)點hash值不為-1 滞谢,鎖定hash值相同的鏈表頭結點 串稀,進行插入或者更新操作,鏈表過長變?yōu)榧t黑樹
trypersize擴容方法
CAS操作把sizeCtl變?yōu)?1狮杨,表示正在進行初始化 確保只有一個線程進行初始化母截。
創(chuàng)建nextTable 數(shù)組大小為table2倍 ,容量為原來1.5倍
調用transfer方法 把數(shù)據(jù)復制到新數(shù)組?
transfer方法
volatile
1 在工作內存中每次使用變量必須從主內存刷新最新的值
2 每次修改后必須立刻同步會主內存
3 禁止指令從排序
CAS操作
compare and swap ?比較并交換 有三個參數(shù) 1內存中的值 ?2預期的值 ?3 改變后的值
樂觀鎖的一種體現(xiàn) 先操作后檢查橄教。非阻塞式同步
如何保證操作和檢測兩個步驟具備原子性清寇,如果用鎖那就是去意義了
靠硬件來完成原子性,這兩個操作通過一條處理器指令來完成保證了原子性护蝶。
缺點:造成ABA問題华烟,初次讀值為A,并且在準備賦值時檢測到它仍為A持灰,也不能保證它沒有變過盔夜,可能在這段期間內變?yōu)锽
版本號來解決ABA問題,AtomicStampedReference 給變量加上版本號改變一次版本加一?
通過檢查版本號來確定變量改變過沒有堤魁。
版本號的原理在MySQL innodb引擎也有體現(xiàn) innodb 通過MVCC多版本并發(fā)實現(xiàn)高并發(fā)喂链。