AtomicInteger原始碼解析

2021-08-09 03:55:49 字數 1553 閱讀 9786

1.為什麼要使用atomicinteger

使用atomicinteger的原因來自於多執行緒併發情況下帶來的原子性問題(注:所謂原子操作是指不會被

執行緒排程

機制打斷的操作;這種操作一旦開始,就一直執行到結束,中間不會有任何 context switch (切

換到另乙個執行緒

)。舉乙個例子,比如說在多執行緒環境之下有乙個統計使用者數量的計數器,每乙個使用者登入之後都會將這個計數器加一,如果採用普通的int變數來維護這個計數器,每個使用者登入之後進行++i操作,那麼在同時有多個使用者登入的情況下這個計數器可能產生錯誤的值。因為++i不是乙個原子操作,至少分為三步,1.獲取舊值2.舊值加一3.寫回記憶體,這三個操作不是原子的,所以還會帶來可見性問題,所以在其中可能穿插別的執行緒來同時操作這個int值,導致發生一致性問題,所以需要引入atomicinteger。

2.atomicinteger原始碼

atomicinteger通過一種特殊的指令級別的原子操作來完成數字的遞增等操作,擁有以下三個變數

private static final unsafe unsafe = unsafe.getunsafe();//用來提供非安全的基於作業系統的native的方法來更改記憶體中的值

private static final long valueoffset;//計算得到的基於物件起始位址的相對偏移量

static catch (exception ex)

}private volatile int value;//用於存放具體int值的變數,變數具有volatile修飾符,保證了1.可見性2.防止指令重排序

核心操作是cas操作,所以也叫cas變數

public final boolean compareandset(int expect, int update)
cas操作依賴四個變數,this物件指這個atomicinteger變數本身,valueoffset是偏移量,通過這兩個變數可以獲取記憶體中存放這個變數值的具體位址,然後直接更改這個位置的變數值

,後兩個變數提供了判斷條件,之後該記憶體位置的舊值等於expect才可以做更改

在jmm模型中,執行緒只在工作記憶體中修改了這個值,但是由於value是有volatile修飾的,所以這個新的值會強制立即寫回主記憶體,保證了可見性和原子性

基於這個核心操作帶來了兩個操作

public final int getandset(int newvalue) 

}

atomicinteger沒有使用基於阻塞的悲觀鎖機制,而是使用了基於無鎖的樂觀鎖,樂觀鎖基於一種執行緒之間不會衝突的期望,如果衝突的話,會回滾操作,通常都有乙個巨大的迴圈來保證操作的執行

上面的這個操作就基於這個思想,使用了乙個無限迴圈來完成這個操作,每次獲取舊值,然後執行cas操作,成功則退出,這個方法會無限執行直到成功.

相對的還有只執行一次的

public final boolean weakcompareandset(int expect, int update)
不管成功失敗,只執行一次,並返回結果

AbstractCollection原始碼分析

abstractcollection抽象類提供了collection的骨架實現,collection分析請看 這裡直接看它的 是如何實現的.public abstract iterator iterator 該方法沒有實現.public abstract int size 該方法沒有實現.publi...

ThreadPoolExecutor原始碼閱讀

執行緒池解決兩個問題 一是復用執行緒,減少建立銷毀執行緒帶來系統開銷 二是限定系統資源使用邊界,避免大量執行緒消耗盡系統記憶體 適用於互不依賴,執行時間短,不需要對執行緒控制操作的執行緒 新增任務時,1.若執行緒數量小於corepoolsize,則新增執行緒執行任務 2.若執行緒數量大於等於core...

OrangePi One Android 原始碼編譯

一 系統環境搭建參照 二 lichee原始碼編譯 1.檢視help build.sh h2.配置核心 cd linux 3.4 make arch arm menuconfig 進入配置頁面,上下移動列表,空格是選擇列表,左右移動選擇退出選項 3.首次編譯執行清除 在 lichee linux3.4...