相比HashMap而言,是多線程安全的,其底層數據與HashMap的數據結構相同。
JDK1.7之前通過對多個數組分段鎖機制(Segment)來實現的加鎖,默認16個Segment,16個分段,每個Segment對應Node[]數組,每個Segment有一把鎖,也就是說對一個Segment裡的Node[]數組的不同的元素如果要put操作的話,其實都是要競争一個鎖,串行化來處理的。
這種情況下,如果某一時間,同時并發訪問同一個數組段,其最大并發度受段的個數限制,效率還是低。
JDK1.8後實現原理摒棄了這種設計,做了鎖粒度的細化,一個大的數組,數組裡每個元素進行put操作,都是有一個不同的鎖,剛開始進行put的時候,如果當前位置為空,執行CAS操作設值。
如果兩個線程都是在數組[5]這個位置進行put,這個時候如果裡面的值不為null,對數組[5]這個位置進行put的時候,采取的是synchronized(f)加鎖,鎖住這個節點,隻讓一個線程來處理鍊表或紅黑樹。
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//如果當前位置沒有值,就進入CAS操作,成功就結束
if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))//多線程的時候不成功,進入下次for循環設值
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {//鎖住這個節點,隻讓一個線程來處理鍊表或紅黑樹
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; binCount) {
K ek;
if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key, value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
如果是get(key)的時候,是基于Unsafe.getObjectVolatile(),volatile讀機制,來讀取數組裡的節點,而節點裡面的value也是加了volatile,盡可能給你保證說是讀到了其他線程修改的一個最新的值,但是不需要加鎖volatile V val;
Volatile底部實現原理,關注我,後面會講解。
ConcurrentHashMap和Hashtable的區别主要體現在實現線程安全的方式上不同。
1、HashTable内部的方法基本都經過 synchronized 修飾。而synchronized關鍵字加鎖是對整個對象進行加鎖,也就是說在進行put等修改Hash表的操作時,鎖住了整個Hash表,從而使得其表現的效率低下。
2、ConcurrentHashMap主要從之前的分段加鎖機制優化到現在的鎖粒度的細化。
下篇開始講解List集合相關特性及原理。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!