class accountsafe implements account
@override
public integer getbalance(
) @override
public void withdraw(integer amount)
} // 可以簡化為下面的方法
// balance.addandget(-1 * amount);}
}
前面看到的 atomicinteger 的解決方法,內部並沒有用鎖來保護共享變數的執行緒安全。那麼它是如何實現的呢?
public void withdraw(integer amount)}}
}
其中的關鍵是 compareandset,它的簡稱就是 cas (也有 compare and swap 的說法),它必須是原子操作。
其實 cas 的底層是 lock cmpxchg 指令(x86 架構),在單核 cpu 和多核 cpu 下都能夠保證【比較-交換】的原子性。
在多核狀態下,某個核執行到帶 lock 的指令時,cpu 會讓匯流排鎖住,當這個核把此指令執行完畢,再開啟匯流排。這個過程中不會被執行緒的排程機制所打斷,保證了多個執行緒對記憶體操作的準確性,是原子的。
volatile
獲取共享變數時,為了保證該變數的可見性,需要使用 volatile 修飾。
它可以用來修飾成員變數和靜態成員變數,他可以避免執行緒從自己的工作快取中查詢變數的值,必須到主存中獲取它的值,執行緒操作 volatile 變數都是直接操作主存。即乙個執行緒對 volatile 變數的修改,對另乙個執行緒可見。
注意volatile 僅僅保證了共享變數的可見性,讓其它執行緒能夠看到最新值,但不能解決指令交錯問題(不能保證原子性)
cas 必須借助 volatile 才能讀取到共享變數的最新值來實現【比較並交換】的效果
為什麼無鎖效率高
無鎖情況下,即使重試失敗,執行緒始終在高速執行,沒有停歇,在synchronized 會讓執行緒在沒有獲得鎖的時候,發生上下文切換,進入阻塞。打個比喻執行緒就好像高速跑道上的賽車,高速執行時,速度超快,一旦發生上下文切換,就好比賽車要減速、熄火,等被喚醒又得重新打火、啟動、加速… 恢復到高速執行,代價比較大。
但無鎖情況下,因為執行緒要保持執行,需要額外 cpu 的支援,cpu 在這裡就好比高速跑道,沒有額外的跑道,執行緒想高速執行也無從談起,雖然不會進入阻塞,但由於沒有分到時間片,仍然會進入可執行狀態,還是會導致上下文切換。
cas 的特點
結合 cas 和 volatile 可以實現無鎖併發,適用於執行緒數少、多核 cpu 的場景下。
cas 是基於樂觀鎖的思想:最樂觀的估計,不怕別的執行緒來修改共享變數,就算改了也沒關係,我吃虧點再重試唄。
synchronized 是基於悲觀鎖的思想:最悲觀的估計,得防著其它執行緒來修改共享變數,我上了鎖你們都別想改,我改完了解開鎖,你們才有機會。
cas 體現的是無鎖併發、無阻塞併發,請仔細體會這兩句話的意思
因為沒有使用 synchronized,所以執行緒不會陷入阻塞,這是效率提公升的因素之一
但如果競爭激烈,可以想到重試必然頻繁發生,反而效率會受影響
atomicreference
atomicmarkablereference
atomicstampedreference
aba 問題及解決
主線程僅能判斷出共享變數的值與最初值 a 是否相同,不能感知到這種從 a 改為 b 又 改回 a 的情況,如果主線程希望:
只要有其它執行緒【動過了】共享變數,那麼自己的 cas 就算失敗,這時,僅比較值是不夠的,需要再加乙個版本號
atomicstampedreference
unsafe
unsafe 物件提供了非常底層的,操作記憶體、執行緒的方法,unsafe 物件不能直接呼叫,只能通過反射獲得
JUC中的原子類總結
atomic原子類介紹 atomic 是指乙個操作是不可中斷的。即使是在多個執行緒一起執行的時候,乙個操作一旦開始,就不會被其他執行緒干擾。分類 根據操作的資料型別,可以分為4類 基本資料型別 陣列型別 使用原子的方式更新陣列裡的某個元素 引用型別 物件的屬性修改型別 通過乙個簡單例子帶大家看一下基...
多執行緒(九)JUC包下的類
countdownlatch類位於j a.util.concurrent 包下,利用它可以實現類似計數器的功能。比如有乙個任務 a,它要等待其他 4 個任務執行完畢之後才能執行,此時就可以利用 countdownlatch來實現這種功能了。public static void main string...
Java單例模式結合JUC原子類爆發的新想法
單例模式是23種設計模式中的一種,關於它的介紹,已經數不勝數了,一般網上的實現方式無非是什麼懶漢式,餓漢式,內部類,列舉,volatile加雙重校驗鎖等等,今天我又想到乙個新的實現方式,利用j.u.c提供的原子類,如下 class singleton public static singleton ...