concurrenthashmap是jdk提供的乙個執行緒安全的集合類,它內部的結構原理和我們常用的hashmap基本是一致,那我們可以先來認識一下hashmap,這樣基本上也能大致明白concurrenthashmap了。
hashmap與concurrenthashmap都是用來存放一種鍵值對形式的資料,那它們內部的資料結構是怎麼樣的呢?
首先來看看hashmap的put方法
public v put(k key, v value)
final v putval(int hash, k key, v value, boolean onlyifabsent,
boolean evict)
put方法中呼叫了putval(),putval方法中主要就是往tab中新增元素,而tab是乙個陣列,即hashmap是通過陣列
來存放資料的。陣列下標是由(n - 1) & hash計算得出的,這是對陣列長度求餘的位運算方法,當n為2的倍數時,
hash%n和(n - 1) & hash兩者結果相同,但(n - 1) & hash更高效,所以hashmap的容量都是2的倍數。
陣列的型別是node的,所以hashmap實際儲存的也是一組key,value的node物件,而不單單是value。
node類是實現entry介面,所以我們可以通過map.entryset()方法去遍歷hashmap。
static class nodeimplements map.entry
hashmap是通過陣列存放資料的,資料對應陣列下標的位置由key的hash值決定,但不同key值的hash值是會重複的,
當hash值重複了,資料會怎樣的儲存?
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newnode(hash, key, value, null);
else
}
}...
}
當陣列下標元素不為空時,陣列元素存放的是乙個鍊錶,bincount >= treeify_threshold - 1(即鍊錶長度為8)時
則會轉化為紅黑樹。
結論
hashmap內部的資料結構是由陣列,鍊錶和紅黑樹組成的,當鍊表長度為8時會轉化為紅黑樹。
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newnode(hash, key, value, null);
put方法中這個部分**表明,當兩個執行緒同時判斷該陣列下標元素為空時,就會導致資料被覆蓋掉的情況。
//省略部分**
...else if ((f = tabat(tab, i = (n - 1) & hash)) == null)
else if ((fh = f.hash) == moved)
tab = helptransfer(tab, f);
else
static final boolean castabat(node tab, int i,
nodec, nodev)
我們可以看到concurrenthashmap中判斷陣列下標元素為空時,呼叫的是castabat,而castabat中引用了unsafe
的compareandswapobject方法,unsafe直接對記憶體進行操作,判斷記憶體的資料中是否為空,再進行賦值。
當陣列下標元素不為空則通過關鍵字synchronized來保證並非安全。
結論
concurrenthashmap執行緒安全的原理是通過cas機制和synchronized加鎖。
ConcurrentHashMap原理解析
什麼是concurrenthashmap?眾所周知,hashmap是一種非常高效的資料結構,但是依舊有它的缺陷。那就是在併發插入資料時,有可能會出現帶環鍊錶,讓下一次的讀操作出現死迴圈。於是為了避免hashmap的執行緒安全問題,concurrenthashmap應運而生。concurrenthas...
ConcurrentHashMap 原理簡要分析
在之前寫過hashtable 與hashmap 兩者之間的異同 通過前面文章,可以知道hashmap 中未進行同步考慮,而 hashtable 則使用了 synchronized 帶來的直接影響就是可選擇,我們可以在單執行緒時使用 hashmap 提高效率,而多執行緒時用 hashtable 來保證...
ConcurrentHashMap 的原理和結構
concurrenthashmap 是乙個高效的執行緒安全的hashmap,它的加鎖機制和hashtable不同,後者用的是低效的synchronized,前者用的是lock。接著前一期的hashmap,先簡單介紹下concurrenthashmap結構,再以它們的主要函式 put 和 get為切入...