重入讀寫鎖(ReentrantReadWriteLock)源碼

tryAcquireShared
exclusiveCount(state)!=0&&getExclusiveOwnerThread!=current//如果現在是寫鎖狀態,並且當前線程不是擁有鎖的線程
也就是如果是當前線程是擁有寫鎖的,讀操作也可以進去
if(!readShouldBlock(current)&&CAS(state, state+SHARED_UNIT)){
cacheHoldCounter.count++ //重入計數
return 1;
}
return -1;


tryAcquire
if(state!=0) {
if(exclusiveCount==0||current != getExclusiveOwnerThread)//因爲狀態大於0,但如果寫的部分爲零,說明只有讀鎖,那麼寫鎖肯定進不去。
return false;
}
if(writeShouldBlock(current)||!CAS(c,c+acquires)) {
return false;
}
setExclusiveOwnerThread(current)
return ture


釋放獨佔鎖
nextc = state-release
if(exclusiveCount(nextc)==0) { //判斷低四位的值是否爲0,表示寫鎖重入的次數
setExclusiveOwnerThread(null)
setState(nextc)
return true
} else { //表示還有部分鎖的重入沒解開,所以返回false,不讓AQS去喚醒後面的節點
setState(nextc)
return false
}
如果爲true 將會執行
unparkSuccessor(h)

釋放共享鎖
if(cacheHoldCounter.tryDecrement()<=0) throw new IllegalMonitorStateException //用holdCounter表示重入次數
for(;;) {
if(CAS(state, state-SHARE_UNIT)) //state高四位減去一
return nextc==0 //如果不等於0表示還有部分鎖的重入沒解開,返回false,不讓AQS去喚醒後面的節點
}
如果爲true,將會執行
doReleaseShared()

FairSync
readerShouldBlock(current)//判斷current != head.next.thread
NonfairSync
readerShouldBlock(current)//判斷head.next.nextWaiter != Node.SHARED

總結:ReentrantReadWriteLock比較有意思的幾個地方
1、queue裏面兩種節點:獨佔和共享。獨佔節點喚醒之後,會移除當前節點並繼續執行;共享節點喚醒之後,會移除當前節點並擴散後面的共享節點
2、對state的巧妙設計,高四位用來表示讀鎖狀態,低四位表示寫鎖狀態。
3、對某個線程讀鎖的重入,用AQS現有的結果無法滿足,所以就依靠了ThreadLocal來保存某個線程對某個鎖的持有情況和重入數量。
互斥鎖是可以用一個state變量來表示鎖的重入情況,因爲只對應一個線程,完全可以在獲取和釋放前做current==getExclusiveOwnerThread來判斷
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章