假设这是一个“单例”实现:我能保证这只会调用一次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();
}
}}
编辑:这是一个相当成功的尝试,将复杂得多的代码简化为一个简单的问题示例。有些人注意到我的单例太复杂了;) (实际上也有一个调用reload的quartz计时器,但"reload“实现有点不同)。不管怎样,我得到了我需要的答案,打破了双重检查锁定。
发布于 2009-04-22 08:56:47
这看起来像broken double checked locking。问题是可以在对象完全构造之前分配this.productCatalog。
假设我们有
var foo = new ProductCatalog();
foo.blah = "blah blah";
this.productCatalog = foo;可以将其重新排序为
var foo = new ProductCatalog();
this.productCatalog = foo;
foo.blah = "blah blah";发布于 2009-04-22 06:35:45
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;
}
} 在绝大多数情况下,这已经足够好了,并且您不需要担心内存模型的技术细节。
编辑:至于在不获取读锁的情况下读取写锁中更改的数据是否安全-我怀疑不安全,但我不想肯定地说。使用易失性变量使用普通的(如果仔细的话,在上也是安全的)双重检查锁定的方法有什么好处吗?
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必须是易失性的,这样才能正常工作-我认为这实际上就是您在代码中没有去掉读锁所遗漏的。
发布于 2009-04-22 06:47:09
不,一般来说是不安全的。写锁只保证在写锁被释放之前,没有其他人能够获得读锁或写锁。在代码中不使用readlock就像同步了reload方法,而不同步了get方法。我有点同意Jon Skeet的观点,但这在很大程度上取决于用法。
如果你有很多线程同时调用,你可能想要一个读锁而不是同步它。
编辑:顺便说一下,在Effective第二版中有一个很好的例子来说明如何做到这一点……我还必须在这里纠正自己,在给定上下文的情况下,如果以一种智能的方式完成同步,也会工作得很好(并且writelock可能也会在这种上下文中工作)。
https://stackoverflow.com/questions/775936
复制相似问题