i++是否是線程安全的?爲什麼?
因爲i++ 不是原子性操作 故i++是線程不安全
i++操作分爲三步
讀取i的值 i加1,
寫入i的值 i++是線程不安全的,
多線程i++會造成結果不一致
怎麼解決呢? 加鎖 JAVA原子類
JAVA原子類
AtomicInteger AtomicInteger位於java.util.concurrent.atomic包下,是對int的封裝,提供原子性的訪問和更新操作。
Q: AtomicInteger是怎麼實現原子性操作的?
A:其原子性操作的實現是基於CAS
Q:CAS是什麼?
CAS(compare-and-swap)直譯即比較並交換。 CAS的思想很簡單:三個參數,一個當前內存值V、舊的預期值A、即將更新的值B,當且僅當預期值A和內存值V相同時,將內存值修改爲B並返回true,否則什麼都不做,並返false。在JAVA中,CAS通過調用C++庫實現,由C++庫再去調用CPU指令集。在大多數處理器上 CAS 都是個非常輕量級的操作,這也是其優勢所在。
CAS存在的問題
ABA問題
如果某個線程在CAS操作時發現,內存值和預期值都是A,就能確定期間沒有線程對值進行修改嗎?答案未必,如果期間發生了 A -> B -> A 的更新,僅僅判斷數值是 A,可能導致不合理的修改操作。
Q:怎麼解決呢? A:加版本號。
針對這種情況,Java 提供了 AtomicStampedReference 和AtomicMarkableReference工具類,通過爲引用建立類似版本號的方式,來保證 CAS 的正確性。