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

时间:2013-06-03 16:40:40

标签: java multithreading concurrency locking java.util.concurrent

来自ReentrantReadAndWriteLock class javadoc

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();
}

为什么我们必须在获取注释中写入的写锁之前释放读锁?如果当前线程持有读锁定,那么当其他线程不再读取时,应该允许它获取写锁定,无论当前线程是否还保持读锁定。这是我期望的行为。 最终在第4行和第5行锁定升级并在第14行和第15行锁定降级我希望在ReentrantReadAndWriteLock类内部完成。为什么那是不可能的?

换句话说,我希望代码可以正常工作:

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();
}

这看起来更好,更安全的方式来处理锁定,不是吗?

有人可以解释为什么这个奇怪的实现?感谢。

3 个答案:

答案 0 :(得分:14)

将读锁升级到写锁的问题是,如果两个线程同时尝试执行此操作,则可能导致死锁。请考虑以下顺序:

  1. 主题A:获取读锁
  2. 线程B:获取读锁定(请注意,两个线程现在共享读锁定。)
  3. 线程A:尝试获取写锁定(块B,因为线程B保持读锁定)
  4. 线程B:尝试获取写锁定(块A,因为线程A保持读锁定)
  5. 现在出现了僵局。线程A或B都不能继续,也不会释放读锁定。

答案 1 :(得分:5)

Javadoc明确指出无法将读锁升级到写锁。 原因是因为它可能会造成死锁。

  • 线程1获取读锁定
  • 线程2获取读锁
  • 线程1要求升级锁定以写入
  • 线程2要求升级锁定以写入

两个线程现在正在等待......永远。

答案 2 :(得分:3)

重入允许通过获取写锁定,然后读取锁定然后释放写入锁定,从写入锁定降级到读取锁定。但是,无法从读锁定升级到写锁定(这会导致死锁)。

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