java - 在没有读锁的情况下使用 writeLock 是否安全?

标签 java concurrency

假设这是一个“单例”实现:我能保证这只会调用 productCatalogLoader.load() 一次,并且不会发生空指针吗?有什么办法可以使这更简单吗?

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ProductCatalog productCatalog;

public ProductCatalog get() {
        if (this.productCatalog == null) {
            reload();
         }
        return this.productCatalog;
}                                                         

public void reload() {

    lock.writeLock().lock();
    try {
        if (this.productCatalog != null) return;
        this.productCatalog = productCatalogLoader.load();
    } finally {
        lock.writeLock().unlock();
    }
}

编辑: 这是一次比较成功的尝试,将复杂得多的代码简化为一个简单的问题示例。有几个人发现我的单例太复杂了;)(实际上还有一个 quartz 计时器调用重新加载,但“重新加载”实现与 IRL 有点不同)。无论如何,我得到了我需要的答案,破坏了双重检查锁定。

最佳答案

简化它的最好方法,IMO,是使用“普通”锁,除非你真的有很好的证据表明它会导致瓶颈:

private final Object lock = new Object();
private ProductCatalog productCatalog;

public ProductCatalog get() {
    synchronized (lock) {
        if (this.productCatalog == null) {
            this.productCatalog = productCatalogLoader.load();
        }
        return this.productCatalog;
    }
}                                                         

在绝大多数情况下,这已经足够好了,您无需担心内存模型技术问题。

编辑:至于在不获取读锁的情况下读取写锁中更改的数据是否安全 - 我怀疑不安全,但我不想肯定地说。使用 volatile 变量使用普通(并且在 Java 1.5+ 上是安全的,如果你小心的话)双重检查锁定的方法有什么好处吗?

private final Object lock = new Object();
private volatile ProductCatalog productCatalog;

public ProductCatalog get() {
    if (this.productCatalog == null) {
        synchronized (lock) {
            if (this.productCatalog == null) {
                this.productCatalog = productCatalogLoader.load();
            }
        }
    }
    return this.productCatalog;
}                                                         

我相信这是 Effective Java 第 2 版中推荐的惰性初始化技术,适用于静态初始化器不够用的情况。请注意,productCatalog 必须是易变的才能使其正常工作 - 我认为这有效您没有取消代码中的读取锁定而错过了什么。

关于java - 在没有读锁的情况下使用 writeLock 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/775936/

相关文章:

java - 使用 Spring 3 和 Jackson 1.9 的简单请求中出现错误 406

java - 返回语句是原子的吗?

concurrency - X10 并行处理共享变量

java - 为什么我在 Linux 中使用 ExecutorService 读取线程流时得到 "java.io.IOException: Stream closed"?

java - 实现不抛出 InterruptedException 的接口(interface)时处理 InterruptedException 的正确方法

java - 使用密码执行 Java 进程

java - jfreechart:如何排列两个图?

java - 可复位倒计时闩锁

java - 使用 while 循环报告进度和完成情况是否正确?

java - 方法调用和发送已关闭