java - AQS中源碼疑問
問題描述
在AbstractQueuedSynchronizer類中維護(hù)了一個(gè)用volatile修飾的state狀態(tài),而這個(gè)狀態(tài)有如下的兩種修改方法:
state的set方法:
protected final void setState(int newState) { state = newState;}
CAS方法:
protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}
那么,我的疑問來了,不是說volatile修飾的變量在多線程的單操作中,能夠保證其寫后讀的可見性,即能保證線程安全,為什么還提供了CAS操作能保證線程安全呢?還是我的理解有問題呢?謝謝各位大牛了!
問題解答
回答1:并不沖突吧,setState只是一個(gè)寫操作,并沒有管原來的state,比如state原本是0,線程1和線程2分別讀取了這個(gè)值0,線程1把它set成1,然后線程2打算把它set成2,是可以成功的,盡管state已經(jīng)是1了,而且線程2也知道,但是無所謂,線程2只是把它set成2。下面那個(gè)方法就不會了吧。
回答2:是的,你的理解有問題。
不是說volatile修飾的變量在多線程的單操作中,能夠保證其寫后讀的可見性,即能保證線程安全
能夠保證可見性,不意味著可以保證線程安全。可見性跟線程安全不是同一個(gè)概念。
cas操作,可以劃分為幾個(gè)小操作
比較 expect 和 state 變量當(dāng)前的值,如果相同,繼續(xù)2,如果不同,方法結(jié)束。
為 state 賦值 update
這兩個(gè)操作,如果是多線程并發(fā)調(diào)用,是會有線程安全問題的。這里的 cas 方法利用了 cpu 的 cas 指令,這個(gè)指令是原子操作。可以避免并發(fā)問題。
回答3:簡而言之:
不依賴原始值的可以使用set
依賴原始值的可以使用cas去設(shè)置。本身這是個(gè)樂觀鎖。
相關(guān)文章:
1. css - C#與java開發(fā)Windows程序哪個(gè)好?2. mysql無法添加外鍵3. css - 定位為absolute的父元素中的子元素 如何設(shè)置在父元素的下面?4. java - Mybatis查詢數(shù)據(jù)庫時(shí)出現(xiàn)查詢getInt()的錯(cuò)誤5. JavaScript事件6. javascript - 原生canvas中如何獲取到觸摸事件的canvas內(nèi)坐標(biāo)?7. javascript - es6將類數(shù)組轉(zhuǎn)化成數(shù)組的問題8. 在mac下出現(xiàn)了兩個(gè)docker環(huán)境9. css3 - flex 父標(biāo)簽設(shè)置align-item:center,子元素flex:1,不起作用10. java - 是否類 類型指針、引用作為形參 ,函數(shù)結(jié)束不會自動析構(gòu)類?
