juc在jdk1.8版本中引入了striped64類及其四個實現類longadder、longaccumulator、doubleadder、doubleaccumulator,在原有的atomic***xx等系列上,針對多執行緒併發情況進行了優化。
striped64類被設計用來支援累加器的的併發元件,可以在多執行緒高併發環境下安全的累加計數。striped64內部儲存了base、cells陣列和cellsbusy鎖,計數執行緒首先會嘗試使用cas對base變數進行更改,若更新成功,則計數完成,此時累加器競爭並不激烈。若未更新成功,表示此時競爭較激烈,需要引入cells陣列,將待加數值放入cells內。呼叫累加器的執行緒與cells陣列中的cell一一對應,各執行緒只操作自身對應的cell,striped64根據執行緒的threadlocalrandomprobe屬性值計算雜湊值,將執行緒定位到某個固定的cell上。最後,需要統計計數結果時,若nullcells,則直接返回base值,若nullcells時,則累加cells各索引位置的值後返回。
原始碼分析:
實現基礎:
// cell陣列,若不為null,則為2的n次方.
transient
volatile cell[
] cells;
// 基礎值,在更新操作時基於cas無鎖技術實現原子更新.
transient
volatile
long base;
// cas鎖,用於保護建立或者擴充套件cell表.
transient
volatile
int cellsbusy;
基本方法:
// 依賴cas,更新base的值.
final
boolean
casbase
(long cmp,
long val)
;// 依賴cas,更新cells的值.0表示未被占用,1表示已被占用.
final
boolean
cascellsbusy()
;// 獲取執行緒的threadlocalrandomprobe.
static
final
intgetprobe()
;// 被用來進行建立、初始化、擴充套件.針對long型別.
final
void
longaccumulate
(long x, longbinaryoperator fn,
boolean wasuncontended)
;// 被用來進行建立、初始化、擴充套件.針對double型別.
final
void
doubleaccumulate
(double x, doublebinaryoperator fn,
boolean wasuncontended)
;
longaccumulate和doubleaccumulate實現思路很類似,我們主要針對longaccumulate來逐步解析一下:
final
void
longaccumulate
(long x, longbinaryoperator fn,
boolean wasuncontended)
boolean collide =
false
;// 無限迴圈.
for(;;
)}finally
if(created)
break
;continue;}
} collide =
false;}
// cas已經失敗.需要重新計算索引位置.
elseif(
!wasuncontended)
wasuncontended =
true
;// v = a.value
// a.cas(v, fn)
else
if(a.
cas(v = a.value,
((fn == null)
? v + x :
fn.(v, x)))
)break
;// cells最大長度為cpu的數量,cells != as表示cells已經被更新了.
else
if(n >= ncpu || cells != as)
collide =
false
;elseif(
!collide)
collide =
true
;// cellsbusy未被占用同時更新cellsbusy=1.
else
if(cellsbusy ==0&&
cascellsbusy()
)}finally
collide =
false
;continue;}
// hash過程可能存在衝突,使用此方法可解決問題.
h =advanceprobe
(h);
}// cellsbusy == 0 && cells == as(as在上面if語句裡已經付過錢了).
else
if(cellsbusy ==
0&& cells == as &&
cascellsbusy()
)}finally
if(init)
break;}
// v = base.
// casbase(v, fn);
elseif(
casbase
(v = base,
((fn == null)
? v + x :
fn.(v, x)))
)break;}
}
doubleaccumulate和longaccumulate,差別只在於資料型別的不同,其他邏輯是沒有差別的,大家可以自己看一下這部分的原始碼。
注:文中原始碼均來自於jdk1.8版本,不同版本間可能存在差異。
azkaban web server原始碼解析
azkaban主要用於hadoop相關job任務的排程,但也可以應用任何需要排程管理的任務,可以完全代替crontab。azkaban主要分為web server 任務上傳,管理,排程 executor server 接受web server的排程指令,進行任務執行 1.資料表 projects 工...
JDK LinkedHashMap原始碼解析
今天來分析一下jdk linkedhashmap的源 public class linkedhashmapextends hashmapimplements map可以看到,linkedhashmap繼承自hashmap,並且也實現了map介面,所以linkedhashmap沿用了hashmap的大...
Redux原始碼createStore解讀常用方法
const store createstore reducer,preloadedstate enhancer 直接返回當前currentstate,獲取state值,return state 我覺得應該深轉殖乙個新的物件返回,不然有可能會被外部修改 function getstate consol...