Striped64 深入原始碼解析

2021-10-07 08:00:20 字數 3065 閱讀 2039

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...