重入读写锁(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来判断

猜你喜欢

转载自xussen.iteye.com/blog/2008529