要执行无锁和无等待的惰性初始化,我执行以下操作:
private AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
Foo foo = instance.get();
if (foo == null) {
foo = new Foo(); // create and initialize actual instance
if (instance.compareAndSet(null, foo)) // CAS succeeded
return foo;
else // CAS failed: other thread set an object
return instance.get();
} else {
return foo;
}
}它运行得很好,除了一件事:如果两个线程看到实例null,它们都创建了一个新对象,只有一个幸运地通过CAS操作来设置它,这导致了资源的浪费。
有没有人建议另一种无锁惰性初始化模式,它通过两个并发线程减少创建两个昂贵对象的可能性?
发布于 2015-05-15 18:42:12
如果你想要真正的锁-自由,你将不得不做一些旋转。你可以有一个线程‘胜利’创作权,但其他必须旋转,直到它准备好。
private AtomicBoolean canWrite = new AtomicBoolean(false);
private volatile Foo foo;
public Foo getInstance() {
while (foo == null) {
if(canWrite.compareAndSet(false, true)){
foo = new Foo();
}
}
return foo;
}这显然存在忙于旋转的问题(您可以在其中安睡或屈服),但我可能仍然推荐按需初始化。
发布于 2015-05-15 18:55:14
我认为您需要对对象创建本身进行一些同步。我会这样做:
// The atomic reference itself must be final!
private final AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
Foo foo = instance.get();
if (foo == null) {
synchronized(instance) {
// You need to double check here
// in case another thread initialized foo
Foo foo = instance.get();
if (foo == null) {
foo = new Foo(); // actual initialization
instance.set(foo);
}
}
}
return foo;
}这是一种非常常见的模式,特别是对于懒惰的单身汉。二次检查锁定最小化了实际执行synchronized块的次数。
发布于 2015-05-27 14:38:30
我可能会采用懒惰的init Singleton模式:
private Foo() {/* Do your heavy stuff */}
private static class CONTAINER {
private static final Foo INSTANCE = new Foo();
}
public static Foo getInstance() {
return CONTAINER.INSTANCE;
}实际上,我没有看到使用AtomicReference成员字段的任何理由。
https://stackoverflow.com/questions/30265427
复制相似问题