ReentrantReadWriteLock中,为什么在获取写锁前要释放读锁,查的说会产生死锁,不太明白

来源:6-6 J.U.C之AQS-ReentrantLock与锁-2

茶铺里的水

2018-03-29

* class CachedData {
*   Object data;
*   volatile boolean cacheValid;
*   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
*
*   void processCachedData() {
*     rwl.readLock().lock();
*     if (!cacheValid) {
*       // Must release read lock before acquiring write lock
*       rwl.readLock().unlock();
*       rwl.writeLock().lock();
*       try {
*         // Recheck state because another thread might have
*         // acquired write lock and changed state before we did.
*         if (!cacheValid) {
*           data = ...
*           cacheValid = true;
*         }
*         // Downgrade by acquiring read lock before releasing write lock
*         rwl.readLock().lock();
*       } finally {
*         rwl.writeLock().unlock(); // Unlock write, still hold read
*       }
*     }
*
*     try {
*       use(data);
*     } finally {
*       rwl.readLock().unlock();
*     }
*   }
* }}


写回答

1回答

Jimin

2018-03-29

你好,Reentrant代表重入,字面意思这是一个可重入的读写锁。这里的读写锁都可重入, 线程可同时具有读写锁。

获取 writeLock 时 一定是在没有线程获取 readLock 或 writeLock 时才获取成功,取 readLock 的过程中, 若此时有线程已获取写锁 或 同步等待队列 里面有获取 writeLock 的线程, 则一定会等待获取writeLock成功并释放或放弃获取 后才能获取(死锁时, 已获取 readLock 的线程还能重复获取 readLock)

基于上面的特性,我们再来说死锁的问题:

线程A获取 readLock 成功,然后开始获取 writeLock, 这时发现 readLock 已经 readLock 已经被线程获取, 且writeLock没有被人获取(方法 tryAcquire c != 0 && w == 0), 直接加入到同步等待队列 里面, 并且一直等待 readLock 的释放(等待自己readLock释放, 其实是不可能的)

线程B之后第一次获取 readLock, 此时同步等待队列里面有等待的节点, 就在那一直等待。

死锁就出现了。

1
1
茶铺里的水
谢谢老师,解答非常详细!!!
2018-03-29
共1条回复

Java高并发编程,构建并发知识体系,提升面试成功率

构建完整并发与高并发知识体系,倍增高薪面试成功率!

3923 学习 · 832 问题

查看课程