首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不允许ReadWriteLock升级?

为什么不允许ReadWriteLock升级?
EN

Stack Overflow用户
提问于 2015-10-26 09:43:12
回答 1查看 2.6K关注 0票数 10

ReadWriteLock降级是ReentrantReadWriteLock实现所允许的(下面示例中的tryLock()总是返回true):

代码语言:javascript
复制
void downgrade(final ReadWriteLock readWriteLock) {
    boolean downgraded = false;
    readWriteLock.writeLock().lock();
    try {
        // Always true, as we already hold a W lock.
        final boolean readLockAcquired = readWriteLock.readLock().tryLock();
        if (readLockAcquired) {
            // Now holding both a R and a W lock.
            assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 1;
            assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 1;

            readWriteLock.writeLock().unlock();
            downgraded = true;
            try {
                // Now do some work with only a R lock held
            } finally {
                readWriteLock.readLock().unlock();

                assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0;
                assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0;
            }
        }
    } finally {
        if (!downgraded) {
            // Never (we were holding a W lock while trying a R lock).
            readWriteLock.writeLock().unlock();
        }
        assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0;
        assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0;
    }
}

不允许以类似方式升级锁的背后是什么想法?下面的写锁的tryLock()方法可以安全地返回true w/o,在没有其他线程持有读锁的情况下存在死锁的风险:

代码语言:javascript
复制
void upgrade(final ReadWriteLock readWriteLock) {
    readWriteLock.readLock().lock();
    try {
        // Always false: lock upgrade is not allowed
        final boolean writeLockAcquired = readWriteLock.writeLock().tryLock();
        // ...
    } finally {
        readWriteLock.readLock().unlock();
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-11 23:09:00

首先,让我们注意升级和降级在ReadWriteLock的语义复杂性方面并不等同。

为了完成降级事务,您不需要避免争用,因为您已经拥有锁上升级最多的特权,并且保证您是当前执行降级的唯一线程。升级的情况并非如此,因此支持升级的机制自然需要更复杂(或者更聪明)。

要想可用,升级机制需要防止死锁,以防两个读取线程同时尝试升级(或者专门针对ReentrantReadWriteLock,以防单个读取线程持有多个读取锁试图升级)。此外,该机制需要指定如何处理失败的升级请求(它的读锁是否无效),这就更不简单了。

正如您现在可能看到的,在ReentrantReadWriteLock中完全处理这些问题至少是不方便的(尽管如此,这就是.NET的ReaderWriterLock。我的猜测是,虽然在一些微不足道的情况下,final boolean writeLockAcquired = readWriteLock.writeLock().tryLock();可能会成功,但对于普通用途来说,可升级性仍然不够好--在足够激烈的争论下,如果您输掉了写锁的竞赛,您就处于同一条船上,就好像您打开了读锁,并试图获得写锁(给其他人留下了潜入写入锁并在两者之间获取写锁的机会)。

提供锁可升级性的一种很好的方法是只允许一个线程尝试升级--这是ReentrantReadWriteUpdateLock所做的或者.NET的ReaderWriterLockSlim所做的。不过,我仍然推荐Java 8的StampedLock为:

  • 在低争用情况下,它的乐观读取比使用读锁快得多。
  • 它的API对升级的限制要小得多(从乐观阅读到读锁再到写锁)
  • 我多次尝试创建一个现实的JMH基准测试,其中其他类似的锁几乎总是失败的。
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33342593

复制
相关文章

相似问题

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