【问题标题】:is lock downgrading necessary when using ReentrantReadWriteLock使用 ReentrantReadWriteLock 时是否需要降级锁定
【发布时间】:2018-01-20 16:25:44
【问题描述】:

ReentrantReadWriteLock 的文档中有一个关于锁降级的示例用法(请参阅this)。

class CachedData {
    final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    Object data;
    volatile boolean cacheValid;

    void processCachedData() {
        rwl.readLock().lock();
        if (!cacheValid) {
            // Must release read lock before acquiring write lock
            rwl.readLock().unlock();
            rwl.writeLock().lock();
            try {
                // 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
                rwl.readLock().lock();//B
            } finally {//A
                rwl.writeLock().unlock(); // Unlock write, still hold read
            }
        }
        try {
            use(data);
        } finally {//C
            rwl.readLock().unlock();
        }
    }
}

如果我将Object data更改为volatile Object data,是否还需要将写锁降级为读锁?


更新

我的意思是,如果我将volatile 添加到data,在我在评论A 处释放finally 块中的写锁之前,我是否仍需要获取读锁作为comment@987654329 处的代码@andC 做吗?或者代码可以利用volatile

【问题讨论】:

    标签: java reentrantreadwritelock


    【解决方案1】:

    不,无论您是否降级,都不需要volatile(锁定已经保证了对data 的线程安全访问)。它也无助于 原子性,这是获取-读取-然后-写入-锁定模式所做的(这也是问题的重点)。

    你说的是需要降级,就像这是一件坏事。您可以保持写锁定而不是降级,一切都会正常工作。你只是保留了一个不必要的强锁,而读锁就足够了。

    您不需要降级为读锁,但如果您不这样做,它会降低您的代码效率:如果use(data) 需要 2 秒(很长一段时间),那么您无需降级锁定每次刷新缓存时阻止所有其他读取器 2 秒。

    如果你的意思是为什么在缓存刷新完成后你甚至需要读锁,那是因为否则另一个线程可能会启动新的缓存刷新(因为不会有任何锁),而我们'仍在处理use(data)

    在给定的示例代码中,无法确定它是否真的重要,因为没有足够的信息,但它会为方法创建一个可能的附加状态,这不是一个优势:

    • 一个或多个线程在use(data) 中,具有读锁
    • 一个线程正在刷新缓存,有写锁
    • 一个线程在use(data) 中没有锁,一个线程正在用写锁刷新缓存

    【讨论】:

    • 哦,我的问题不清楚。我的意思是如果我使用volatiledata,我是否还需要在释放写锁之前获取读锁。我不知道可见性是否volatile提供是否可以保护data
    • @muzi_chelsea 您需要锁,因为这里有 两个 变量必须保持同步并作为一个原子操作进行读写。如果只有一个,你就不会。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 1970-01-01
    相关资源
    最近更新 更多