首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在没有读锁的情况下使用writeLock安全吗?

在没有读锁的情况下使用writeLock安全吗?
EN

Stack Overflow用户
提问于 2009-04-22 06:28:31
回答 4查看 1.3K关注 0票数 1

假设这是一个“单例”实现:我能保证这只会调用一次productCatalogLoader.load(),而且不会出现空指针吗?有没有办法让这一切变得更简单?

代码语言:javascript
复制
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();
    }
}

}

编辑:这是一个相当成功的尝试,将复杂得多的代码简化为一个简单的问题示例。有些人注意到我的单例太复杂了;) (实际上也有一个调用reload的quartz计时器,但"reload“实现有点不同)。不管怎样,我得到了我需要的答案,打破了双重检查锁定。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-04-22 08:56:47

这看起来像broken double checked locking。问题是可以在对象完全构造之前分配this.productCatalog。

假设我们有

代码语言:javascript
复制
var foo = new ProductCatalog();
foo.blah = "blah blah";
this.productCatalog = foo;

可以将其重新排序为

代码语言:javascript
复制
var foo = new ProductCatalog();
this.productCatalog = foo;
foo.blah = "blah blah";
票数 2
EN

Stack Overflow用户

发布于 2009-04-22 06:35:45

IMO,最简单的方法是使用“普通”锁,除非你真的有很好的证据证明它造成了瓶颈:

代码语言:javascript
复制
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;
    }
}                                                         

在绝大多数情况下,这已经足够好了,并且您不需要担心内存模型的技术细节。

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

代码语言:javascript
复制
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第二版中推荐的延迟初始化技术,用于静态初始化器不够的情况。请注意,productCatalog必须是易失性的,这样才能正常工作-我认为这实际上就是您在代码中没有去掉读锁所遗漏的。

票数 4
EN

Stack Overflow用户

发布于 2009-04-22 06:47:09

不,一般来说是不安全的。写锁只保证在写锁被释放之前,没有其他人能够获得读锁或写锁。在代码中不使用readlock就像同步了reload方法,而不同步了get方法。我有点同意Jon Skeet的观点,但这在很大程度上取决于用法。

如果你有很多线程同时调用,你可能想要一个读锁而不是同步它。

编辑:顺便说一下,在Effective第二版中有一个很好的例子来说明如何做到这一点……我还必须在这里纠正自己,在给定上下文的情况下,如果以一种智能的方式完成同步,也会工作得很好(并且writelock可能也会在这种上下文中工作)。

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

https://stackoverflow.com/questions/775936

复制
相关文章

相似问题

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