首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >可降阶ReadWriteLock的RAII模式

可降阶ReadWriteLock的RAII模式
EN

Code Review用户
提问于 2014-09-01 16:13:14
回答 1查看 540关注 0票数 10

在处理异常时,在Java文档中降级ReentrantReadWriteLock的示例看起来非常不安全。我试着写一个简单的类来简化它。你看到有什么可能失败的案例吗?

我从并发的角度寻找一个回顾,比如如果在降级之前在嵌套锁中抛出异常,这段代码可能会失败。

代码语言:javascript
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

public class RWLockWrapper implements AutoCloseable {
    private final ReadWriteLock rwl;
    private Lock current;

    //RAII
    public RWLockWrapper(ReadWriteLock rwl) {
        this.rwl = rwl;
        this.current = rwl.writeLock();
        this.current.lock();
    }

    public void downgrade() {
        final Lock read = rwl.readLock();
        read.lock();
        try {
            current.unlock();
        } finally {
            current = read;
        }
    }

    @Override
    public void close() {
        current.unlock();
    }
}

像这样使用:

代码语言:javascript
复制
try (RWLockWrapper lock = new RWLockWrapper(rwl)) {
    //write locked

    lock.downgrade();

    //read locked
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2014-09-03 23:51:42

代码的并发性/完整性以及显示它的使用方式都很好。

另一方面,这个设计是很值得怀疑的.我建议您不要使用此模式。

如果您要使用它(这里的评论说它已经使用了),那么我建议您更改名称。它不是包装器,因为您实际上无法通过包装器访问锁。相反,它是一个“锁定的会话”,可以关闭,并被降级。下面的代码看上去/读起来更好:

代码语言:javascript
复制
try (WriteLockedSession sessionlock = new WriteLockedSession(rwl)) {
    //write locked

    writelock.downgrade();

    //read locked
}

这表明构造函数启动写锁,并且会话是“可关闭的”。它也可以被降级。

任何语言中的并发性都是复杂的。Java有四种有详细说明的机制:

  1. 单线程
  2. volatile
  3. synchronized
  4. java.util.concurrent.*
    • “自给”类和结构
    • atomic.*微锁定系统
    • locks.*宏锁定系统

正确使用这些“系统”将允许安全操作。

当事情变得不规范时,问题就会开始发生,并与标准的使用模式背道而驰。当人们无法“看到”并发控制时,就会出现bug。

您的类强制执行出乎意料的编码实践:

  • 它隐藏了锁
  • 它需要使用带资源的试用模式,而不是尝试-最终。
  • 它假定ReadWriteLock的实现与您的算法兼容。

最后一点意义重大..。ReadWriteLock没有指定锁的实现细节,它只是一个接口。此外,它还明确表示实现可以施加限制。

尽管读写锁的基本操作是直截了当的,但实现必须作出许多决策.:

  • 它能在保持写锁的同时获得读锁吗?
  • 可以将写锁降级为读锁而不允许中间的写入器吗?
  • ……

您的代码假设上面的假设只是有效的,但这是一个错误的假设。

我建议您更改代码以处理并发包中提供的实际ReentrantReadWriteLock实现。它确实支持这些东西。

此外,降级方法中的以下代码也是不必要的:

try { current.unlock(); } finally { current = read; }

这可能只是:

代码语言:javascript
复制
        current.unlock();
        current = read;

unlock()不能抛出异常。如果是这样的话,Java中的其他东西也会被破坏。try/finally块表示您正在以某种方式保护锁,但它只是软绵绵。

指出这些问题后,考虑另一种选择.

那么,标准模式到底有什么问题呢?

考虑到这一点:

代码语言:javascript
复制
ReentrantReadWriteLock rwl = .....

Lock lock = rwl.writeLock();
lock.lock();
try {

    rwl.readLock().lock();
    lock.unlock();
    lock = rwl.readLock()

} finally {
    lock.unLock();
}

上面有一个try

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

https://codereview.stackexchange.com/questions/61702

复制
相关文章

相似问题

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