mre*_*mre 42 java thread-safety lazy-initialization
有哪些推荐的方法可以实现线程安全的延迟初始化?例如,
// Not thread-safe
public Foo getInstance(){
if(INSTANCE == null){
INSTANCE = new Foo();
}
return INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*ans 53
对于单例,通过将任务委派给JVM代码进行静态初始化,可以得到一个优雅的解决方案.
public class Something {
private Something() {
}
private static class LazyHolder {
public static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
Run Code Online (Sandbox Code Playgroud)
看到
http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
以及Crazy Bob Lee的博客文章
http://blog.crazybob.org/2007/01/lazy-loading-singletons.html
Ken*_*hoi 49
如果您正在使用Apache Commons Lang,那么您可以使用ConcurrentInitializer的一种变体,如LazyInitializer.
例:
ConcurrentInitializer<Foo> lazyInitializer = new LazyInitializer<Foo>() {
@Override
protected Foo initialize() throws ConcurrentException {
return new Foo();
}
};
Run Code Online (Sandbox Code Playgroud)
您现在可以安全地获取Foo(仅初始化一次):
Foo instance = lazyInitializer.get();
Run Code Online (Sandbox Code Playgroud)
如果你使用谷歌的番石榴:
Supplier<Foo> fooSupplier = Suppliers.memoize(new Supplier<Foo>() {
public Foo get() {
return new Foo();
}
});
Run Code Online (Sandbox Code Playgroud)
然后叫它 Foo f = fooSupplier.get();
来自Suppliers.memoize javadoc:
返回一个供应商,它缓存在第一次调用get()期间检索到的实例,并在后续调用get()时返回该值.返回的供应商是线程安全的.委托的get()方法最多只能调用一次.如果delegate是先前调用memoize创建的实例,则直接返回.
Ale*_*you 28
这可以通过使用AtomicReference实例持有者以无锁方式完成:
// in class declaration
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的主要缺点是多个线程可以同时实例化两个或多个Foo对象,并且只有一个可以设置,因此如果实例化需要I/O或其他共享资源,则此方法可能不合适.
另一方面,这种方法是无锁且无等待的:如果首先进入此方法的一个线程被卡住,它将不会影响其他线程的执行.
最简单的方法是使用静态内部持有者类:
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
}
Run Code Online (Sandbox Code Playgroud)
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
Run Code Online (Sandbox Code Playgroud)
这称为双重检查!检查这个http://jeremymanson.blogspot.com/2008/05/double-checked-locking.html
如果您在项目中使用 lombok,则可以使用此处描述的功能。
您只需创建一个字段,对其进行注释@Getter(lazy=true)并添加初始化,如下所示:
@Getter(lazy=true)
private final Foo instance = new Foo();
您必须仅使用 getter 来引用字段(请参阅 lombok文档中的注释),但在大多数情况下,这就是我们所需要的。
| 归档时间: |
|
| 查看次数: |
40467 次 |
| 最近记录: |