首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在ReentrantReadWriteLock中,readLock()应该在writeLock().lock()之前被解锁?

为什么在ReentrantReadWriteLock中,readLock()应该在writeLock().lock()之前被解锁?
EN

Stack Overflow用户
提问于 2013-06-04 00:40:40
回答 3查看 1.2K关注 0票数 6

ReentrantReadWriteLock class javadoc

代码语言:javascript
复制
void processCachedData() {
  rwl.readLock().lock();
  if (!cacheValid) {
     // Must release read lock before acquiring write lock
5:   rwl.readLock().unlock();
6:   rwl.writeLock().lock();
     // 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
14:  rwl.readLock().lock();
15:  rwl.writeLock().unlock(); // Unlock write, still hold read
  }

  use(data);
  rwl.readLock().unlock();
}

为什么我们必须在获取评论中所写的写锁之前释放读锁?如果当前线程持有读锁,则应允许它在其他线程不再读取时获取写锁,而不管当前线程是否也持有读锁。这是我所期望的行为。

我预计第5行和第6行的锁升级和第14行和第15行的锁降级将在ReentrantReadWriteLock类内部完成。为什么这不可能呢?

换句话说,我希望代码能像这样正常工作:

代码语言:javascript
复制
void processCachedData() {
  rwl.readLock().lock();
  if (!cacheValid) {
     // The readlock is upgraded to writeLock when other threads 
     // release their readlocks.
     rwl.writeLock().lock();
     // no need to recheck: other threads can't have acquired  
     // the write lock since this thread still holds also the readLock!!!
     if (!cacheValid) {  
       data = ...
       cacheValid = true;
     }
     // Downgrade by acquiring read lock before releasing write lock
     rwl.writeLock().unlock(); // Unlock write, still hold read
  }

  use(data);
  rwl.readLock().unlock();
}

这看起来是一种更好、更安全的处理锁定的方法,不是吗?

有人能解释一下这个奇怪的实现的原因吗?谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-06-04 00:49:08

将读锁升级为写锁的问题是,如果两个线程同时尝试这样做,可能会导致死锁。请考虑以下顺序:

  1. 线程A:获取读锁
  2. 线程B:获取读锁(注意两个线程现在共享读锁)。
  3. 线程A:尝试获取写锁(由于线程B持有读锁而阻塞)
  4. 线程B:尝试获取写锁(由于线程A持有读锁而阻塞)

现在出现了一个死锁。线程A和线程B都不能继续,也不会释放读锁。

票数 16
EN

Stack Overflow用户

发布于 2013-06-04 00:49:52

Javadoc明确声明将读锁升级为写锁是不可能的。这样做的原因是因为它会造成死锁。

  • 线程1获取读锁
  • 线程2获取读锁
  • 线程1请求升级锁为写
  • 线程2请求升级锁为写

两个线程现在都在等待对方...永远不变。

票数 5
EN

Stack Overflow用户

发布于 2013-06-04 00:43:19

可重入性允许从写锁降级为读锁,方法是先获取写锁,然后获取读锁,然后释放写锁。但是,从读锁升级到写锁是不可能的(这会导致死锁)。

来源:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16901640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档