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来判断
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来判断