hashtable所以方法預設加sychronized,
hashmap預設沒有加鎖,
而synchronizedhashmap預設是collections.synchronizedmap(mapmap)返回乙個同步map。
currenthashmap是多線**正用的,本來是拉鍊表,jdk1.8後變成紅黑樹.
concurrenthashmap相比hashmap而言,是多執行緒安全的,其底層資料與hashmap的資料結構相同,資料結構如下:
concurrenthashmap的資料結構(陣列+鍊錶+紅黑樹),桶中的結構可能是鍊錶,也可能是紅黑樹,紅黑樹是為了提高查詢效率。
jdk1.5中的實現
concurrenthashmap使用的是分段鎖技術,將concurrenthashmap將鎖一段一段的儲存,然後給每一段資料配一把鎖(segment),當乙個執行緒占用一把鎖(segment)訪問其中一段資料的時候,其他段的資料也能被其它的執行緒訪問,預設分配16個segment。預設比hashtable效率提高16倍。
concurrenthashmap的結構圖如下(網友貢獻的圖,哈):
jdk1.8中的實現
concurrenthashmap取消了segment分段鎖,而採用cas和synchronized來保證併發安全。資料結構跟hashmap1.8的結構一樣,陣列+鍊錶/紅黑二叉樹。
synchronized只鎖定當前鍊錶或紅黑二叉樹的首節點,這樣只要hash不衝突,就不會產生併發,效率又提公升n倍。
jdk1.8的concurrenthashmap的結構圖如下:
treebin:紅黑二叉樹節點concurrenthashmap 類結構參照hashmap,這裡列出hashmap沒有的幾個屬性。node:鍊錶節點
/**
* table initialization and resizing control. when negative, the
* table is being initialized or resized: -1 for initialization,
* else -(1 + the number of active resizing threads). otherwise,
* when table is null, holds the initial table size to use upon
* creation, or 0 for default. after initialization, holds the
* next element count value upon which to resize the table.
hash表初始化或擴容時的乙個控制位標識量。
負數代表正在進行初始化或擴容操作
-1代表正在初始化
-n 表示有n-1個執行緒正在進行擴容操作
正數或0代表hash表還沒有被初始化,這個數值表示初始化或下一次進行擴容的大小
*/private transient volatile int sizectl;
// 以下兩個是用來控制擴容的時候 單執行緒進入的變數
/*** the number of bits used for generation stamp in sizectl.
* must be at least 6 for 32bit arrays.
*/private static int resize_stamp_bits = 16;
/*** the bit shift for recording size stamp in sizectl.
*/private static final int resize_stamp_shift = 32 - resize_stamp_bits;
/** encodings for node hash fields. see above for explanation.
*/static final int moved = -1; // hash值是-1,表示這是乙個forwardnode節點
static final int treebin = -2; // hash值是-2 表示這時乙個treebin節點
分析**主要目的:分析是如果利用cas和synchronized進行高效的同步更新資料。下面插入資料原始碼:
public v put(k key, v value)
/** implementation for put and putifabsent */
final v putval(k key, v value, boolean onlyifabsent)
//檢查到內部正在移動元素(node 陣列擴容)
else if ((fh = f.hash) == moved)
//幫助它擴容
tab = helptransfer(tab, f);
else {
v oldval = null;
//鎖住鍊錶或紅黑二叉樹的頭結點
synchronized (f) {
//判斷f是否是鍊錶的頭結點
if (tabat(tab, i) == f) {
//如果fh>=0 是鍊錶節點
if (fh >= 0) {
bincount = 1;
//遍歷鍊錶所有節點
for (node e = f;; ++bincount) {
k ek;
//如果節點存在,則更新value
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.
多執行緒與高併發7 容器
queue佇列 主要就是為高併發而存在,有進有出。deque雙關佇列 頭和尾都可以訪問 blockingqueue阻塞佇列 priorityqueue優先佇列 按照順序先入先出 delayqueue延遲佇列 佇列中的物件只有到期之後才能被取走 一代同步容器,所有的方法均上鎖,基本不用 hashtab...
併發與多執行緒
標頭檔案 include c 11建立執行緒 thread th myfunc 建立乙個子執行緒,並且子執行緒開始執行,引數為可呼叫物件,可以是函式,仿函式,lambda表示式,下面給出例子示例 void myfunc class myclass void func intmain thread t...
多執行緒與併發
執行緒的部分功能就是實現併發,多個執行緒在每個執行緒上都可以執行小段的 處理器很快的在各個執行緒間進行切換,像是在同時執行,其實所有的 ios 裝置都還有第二個處理器,顯示介面卡 gpu 與顯示相關的 都由 gpu 獨立於主處理器之外執行.主線程自動有乙個執行迴圈 run loop 乙個run lo...