【发布时间】:2010-10-02 15:53:26
【问题描述】:
我目前在我的代码中使用ReentrantReadWriteLock 来同步对树状结构的访问。这个结构很大,可以同时被许多线程读取,偶尔会修改其中的一小部分——所以它似乎很适合读写习惯。我知道对于这个特定的类,不能将读锁提升为写锁,因此根据 Javadocs,必须在获得写锁之前释放读锁。我之前已经在不可重入上下文中成功使用过这种模式。
然而,我发现如果不永久阻塞,我就无法可靠地获取写锁。由于读锁是可重入的,我实际上是这样使用它的,所以简单的代码
lock.getReadLock().unlock();
lock.getWriteLock().lock()
如果我以可重入方式获得了读锁,则可以阻止。每次解锁调用只会减少保持计数,并且只有在保持计数达到零时才会真正释放锁。
EDIT 澄清这一点,因为我认为我最初解释得不是很好 - 我知道这个类中没有内置的锁升级,我必须简单地释放读锁并获得写锁。我的问题是/是不管其他线程在做什么,调用 getReadLock().unlock() 可能实际上不会释放 this 线程对锁的持有,如果它重新获得它,在这种情况下调用getWriteLock().lock()将永远阻塞,因为该线程仍然持有读锁并因此阻塞自己。
例如,这段代码 sn-p 永远不会到达 println 语句,即使在没有其他线程访问锁的情况下运行单线程:
final ReadWriteLock lock = new ReentrantReadWriteLock();
lock.getReadLock().lock();
// In real code we would go call other methods that end up calling back and
// thus locking again
lock.getReadLock().lock();
// Now we do some stuff and realise we need to write so try to escalate the
// lock as per the Javadocs and the above description
lock.getReadLock().unlock(); // Does not actually release the lock
lock.getWriteLock().lock(); // Blocks as some thread (this one!) holds read lock
System.out.println("Will never get here");
所以我问,有没有一个很好的成语来处理这种情况?具体来说,当一个持有读锁的线程(可能是可重入的)发现它需要进行一些写操作,因此想要“挂起”自己的读锁以获取写锁(根据需要在其他线程上阻塞以释放他们对读锁的持有),然后“拿起”它在相同状态下对读锁的持有?
既然这个 ReadWriteLock 实现是专门设计为可重入的,那么当可以重入获取锁时,肯定有一些明智的方法可以将读锁提升为写锁吗?这是关键部分,这意味着幼稚的方法不起作用。
【问题讨论】:
-
您的问题是否来自尝试在您正在写入的同一线程上执行不可知数量的读取锁定。你不能在另一个线程上写吗?
标签: java concurrency reentrantreadwritelock