Jdk源码分析

文章40 |   阅读 14787 |   点赞0

来源:https://yumbo.blog.csdn.net/category_10384063.html

ReentrantReadWriteLock常见问题,源码级别的讲解

x33g5p2x  于2021-12-18 转载在 其他  
字(1.1k)|赞(0)|评价(0)|浏览(313)

ReentrantReadWriteLock源码注释

ReentrantReadWriteLock中利用state的前16位表示读锁、后16位表示写锁
而下面图片源码如果出现w就代表写锁的个数,r是读锁的个数
写锁加锁失败的情况

读锁没有释放,加写锁则会失败

下面的方法是尝试加写锁时会执行的方法,判断的方法如下

public final void acquire(int arg) {
    if (!tryAcquire(arg)) { // 尝试加锁,失败则需要进入队列
        acquire(null, arg, false, false, false, 0L);
    }
}

判断中的方法如下

c!=0说明加过锁,如果接着w==0就会直接返回false。这种情况就是说明加的全是读锁。
对应着读写操作
因此上面的if代码块内的方法会被执行,也就是会将当前获取写锁的线程加入阻塞队列中去。

加过写锁,当前线程不是持有写锁的线程,加写锁失败

这种好理解对应写写操作,也就是c!=0、可 w!=0 但 current != getExclusiveOwnerThread()成立
写锁加锁成功的情况

即没加写锁也没加过读锁,写锁加锁成功

也就是对应着c=0这种情况,会直接到后面,最终返回true

加过写锁,并且当前线程就是那个持有写锁的线程

要想不执行return false 就必须或两边都是false,也就是要w!=0当前线程=持有写锁的线程,相当于写锁重入,然后更新state中的写锁个数
读锁加锁成功的情况

public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0) // 尝试获取读锁,失败则需要将节点加入aqs队列
        acquire(null, arg, true, false, false, 0L);
}

存在写锁、当前线程持有写锁,则当前线程加读锁成功

持有写锁的线程拥有最高权限,自然再加读锁是没有关系的。

不存在写锁、加读锁成功。

有一种情况比较特殊,如果读锁设置为排他的,那么会导致执行方法最后以一行的return 传入线程。
目的尝试排他读的抢占读锁是成功,失败也会进入队列。

读排他似乎我没看到ReentrantReadWriteLock对读锁的定义,虽然设计了,但似乎没有这种情况(如果有误望指正)。
读锁加锁失败的情况

写锁不为0,且当前线程不是持有写锁的线程,则加锁失败

对应着写读状态,exclusiveCount(c) != 0说明已经加过写锁,并且当前线程不是这个写锁的持有者线程。

讲道理的方式理解:如果当前线程是持有写锁的那个线程,自然抢占读锁自然没问题,因为持有写锁就相当于独占(想怎么写、想怎么读都随便)

相关文章