2.為什麼concurrenthashmap比hashtable高效
它使用segment和hashentry兩個陣列組成,加鎖同步加儲存k,v鍵值。
每乙個concurrenthashmap都包含了乙個segment陣列,在segment陣列中每乙個segment物件則又包含了乙個hashentry陣列,
而在hashentry陣列中,每乙個hashentry物件儲存k-v資料的同時又形成了鍊錶結構,此時與hashmap結構相同。
在多執行緒中,每乙個segment物件守護了乙個hashentry陣列,當對concurrenthashmap中的元素修改時,在獲取到對應的segment陣列角標後,都會對此segment物件加鎖,之後再去操作後面的hashentry元素,這樣每乙個segment物件下,都形成了乙個小小的hashmap。
//預設最大的容量
private static final int maximum_capacity = 1 << 30;
//預設初始化的容量
private static final int default_capacity = 16;
//最大的陣列可能長度
static final int max_array_size = integer.max_value - 8;
//預設的併發級別,目前並沒有用,只是為了保持相容性
private static final int default_concurrency_level = 16;
//和hashmap一樣,負載因子
private static final float load_factor = 0.75f;
//和hashmap一樣,鍊錶轉換為紅黑樹的閾值,預設是8
static final int treeify_threshold = 8;
//紅黑樹轉換鍊錶的閥值,預設是6
static final int untreeify_threshold = 6;
//進行鍊錶轉換最少需要的陣列長度,如果沒有達到這個數字,只能進行擴容
static final int min_treeify_capacity = 64;
//table擴容時, 每個執行緒最少遷移table的槽位個數
private static final int min_transfer_stride = 16;
//感覺是用來計算偏移量和執行緒數量的標記
private static int resize_stamp_bits = 16;
//能夠調整的最大執行緒數量
private static final int max_resizers = (1 << (32 - resize_stamp_bits)) - 1;
//記錄偏移量
private static final int resize_stamp_shift = 32 - resize_stamp_bits;
//值為-1, 當node.hash為moved時, 代表著table正在擴容
static final int moved = -1;
//treebin, 置為-2, 代表此元素後接紅黑樹
static final int treebin = -2;
//感覺是佔位符,目前沒看出來明顯的作用
static final int reserved = -3;
//主要用來計算hash值的
static final int hash_bits = 0x7fffffff;
//節點陣列
transient volatile node table;
//table遷移過程臨時變數, 在遷移過程中將元素全部遷移到nexttable上
private transient volatile node nexttable;
//基礎計數器
private transient volatile long basecount;
//table擴容和初始化的標記,不同的值代表不同的含義,預設為0,表示未初始化
//-1: table正在初始化;小於-1,表示table正在擴容;大於0,表示初始化完成後下次擴容的大小
private transient volatile int sizectl;
//table容量從n擴到2n時, 是從索引n->1的元素開始遷移, transferindex代表當前已經遷移的元素下標
private transient volatile int transferindex;
//擴容時候,cas鎖標記
private transient volatile int cellsbusy;
//計數器表,大小是2次冪
private transient volatile countercell countercells;
final v putval
(k key, v value,
boolean onlyifabsent)
elseif(
(fh = f.hash)
== moved)
tab =
helptransfer
(tab, f)
;else
node
pred = e;if(
(e = e.next)
== null)}}
else
if(f instanceof
treebin)}
}}if(bincount !=0)
}}addcount
(1l, bincount)
;return null;
}
segment分段鎖繼承reentrantlock,在併發數高的時候,reentrantlock比syncronized總體開銷要小一些。 執行緒安全性
定義 當多個執行緒訪問某個類時,不管執行環境採用何種呼叫方式或者這些執行緒如何交替執行,並且在主調 中不需要任何額外的同步或者協同,這個類都能表現出正確的行為,那麼就稱這個類是執行緒安全的。主要表現三個方面 atomic cas unsafe.compareandswapint atomiclong...
執行緒安全性
執行緒安全性 當多個執行緒訪問某個類時,這個類始終都能表現出正確的行為,那麼稱這個類是執行緒安全的。執行緒不安全產生的問題 競態條件 由於不恰當的執行時序而出現不正確的結果。大多數競態條件的本質是基於一種可能失效的觀察結果來做出判斷或者執行某個計算。常見先檢查後執行,延遲初始化 單例模式 讀取 修改...
STL 執行緒安全性
stl 執行緒安全性 摘錄 在所有的主流stl實現方案中,幾乎所有的容器都是執行緒安全的 1 乙個執行緒讀寫乙個例項時,另乙個執行緒可以讀寫另乙個例項。2 多個執行緒可以在同時讀同乙個container。3 多個執行緒讀寫同乙個container時,你應該負責安排互斥性操作。乙個特例是std str...