【Java并發(fā)】面試官問我CAS、樂觀鎖、悲觀鎖,我反手就是騎臉輸出

面試常問:
- 了解CAS嗎?談?wù)劺斫?/li>
- 用過AQS嗎?舉個(gè)例子
- 讀過JUC源碼嗎?具體實(shí)現(xiàn)

P.S. 互斥鎖:比如synchronized關(guān)鍵字、ReentrantLock
參考:https://blog.csdn.net/jiyiqinlovexx/article/details/51010176
悲觀鎖(Pessimistic Concurrency Control)
悲觀:OS認(rèn)為,若不嚴(yán)格同步(sync)線程調(diào)用,則一定會(huì)產(chǎn)生異常。
故:互斥鎖將一個(gè)資源鎖定,僅供一個(gè)線程調(diào)用,阻塞其他線程。



compare and swap
oldValue:代表之前讀到的資源對(duì)象的狀態(tài)值
newValue:代表享要將資源對(duì)象的狀態(tài)值更新后的值

“此時(shí)AB線程爭(zhēng)搶著去修改資源對(duì)象的狀態(tài)值,然后占用它”

設(shè)a搶到了時(shí)間片,
a 對(duì)比 對(duì)象狀態(tài)值=0, oldValue=0
二者compare,結(jié)果相等,符合預(yù)期,則swap對(duì)象狀態(tài)值為1
b 對(duì)比 對(duì)象狀態(tài)值=1, oldValue=0。
二者compare,結(jié)果不等,搶占失敗,放棄swap操作。
實(shí)際應(yīng)用,通常會(huì)讓b進(jìn)行自旋(不斷第重試cas操作,且配置次數(shù)避免死循環(huán))


沒有同步操作,還是線程不安全
(若同時(shí)搶到,則同時(shí)swap為1,同步失敗)

故,要是CAS線程安全,則:
campare和swap必須“被綁定”
- campare & swap這個(gè)操作,必須滿足同一時(shí)刻只能允許1個(gè)線程在進(jìn)行
即 CAS必須是原子性的

各種架構(gòu)的CPU提供了指令級(jí)別的CAS原子操作:
- x86: cmpxchg
- arm: LL/SC
即無(wú)需通過OS的同步原語(yǔ)(mutex),CPU硬件原生支持CAS,上層進(jìn)行調(diào)用即可
但這不代表“無(wú)鎖”能代替“有鎖”。
樂觀鎖(Optimistic Concurrency Control):
- 不會(huì)鎖定資源
- 當(dāng)線程想要修改共享資源的對(duì)象時(shí),總是會(huì)樂觀地認(rèn)為,對(duì)象狀態(tài)值沒有被其他線程修改過,而是每次都會(huì)自己主動(dòng)嘗試去compare狀態(tài)值

樂觀“鎖”取名不恰當(dāng):因?yàn)槠洳]有用到鎖,實(shí)為無(wú)鎖的同步機(jī)制
示例需求:使用3個(gè)線程,將一個(gè)值,從0累加到1000
錯(cuò)誤1 不使用任何同步機(jī)制

改進(jìn)1 使用互斥鎖同步線程

改進(jìn)2 使用無(wú)鎖編程同步線程
Atomic類是無(wú)鎖編程的輪子
AtomicInteger 底層通過CAS來(lái)實(shí)現(xiàn)同步的計(jì)數(shù)器

Unsafe類型的示例
一個(gè)long類型的offset

直接調(diào)用unsafe對(duì)象的 incrementAndGet方法


自旋循環(huán)次數(shù),可配置,默認(rèn)為10

native boolean compareAndSwapInt
是一個(gè)本地方法
