[英]Lock-free and wait-free thread-safe lazy initialization
要执行无锁和无等待的延迟初始化,请执行以下操作:
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操作来设置它,这会导致浪费资源。
有没有人建议另一种无锁延迟初始化模式,这会降低两个并发线程创建两个昂贵对象的可能性?
如果你想要真正的锁定自由,你将不得不做一些旋转。 您可以拥有一个线程'获胜'创建权,但其他人必须旋转直到它准备就绪。
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;
}
这显然存在繁忙旋转的问题(你可以在那里放一个睡眠或产量),但我可能仍然会建议按需初始化 。
我认为你需要为对象创建本身进行一些同步。 我会做:
// 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
块的次数。
我可能会使用lazy 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成员字段的原因。
如何使用另一个volatile
变量来锁定? 你可以使用新变量进行双锁吗?
我不确定最终结果是否应该以性能为中心,如果下面的是,则不是解决方案。 请你检查两次例如,在第一次检查后调用thread.sleep方法,随机mili秒小于100毫秒。
private AtomicBoolean canWrite = new AtomicBoolean(false);
private volatile Foo foo;
public Foo getInstance() {
if(foo==null){
Thread.Sleep(getRandomLong(50)) // you need to write method for it
if(foo==null){
foo = new Foo();
}
}
return foo;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.