如何实现线程安全的惰性初始化?

2022-08-31 14:51:00

有哪些推荐的方法来实现线程安全的延迟初始化?例如

// Not thread-safe
public Foo getInstance(){
    if(INSTANCE == null){
        INSTANCE = new Foo();
    }

    return INSTANCE;
}

答案 1

对于单例,有一个优雅的解决方案,通过将任务委托给JVM代码进行静态初始化。

public class Something {
    private Something() {
    }

    private static class LazyHolder {
            public static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
            return LazyHolder.INSTANCE;
    }
}

http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

和这篇疯狂的鲍勃李的博客文章

http://blog.crazybob.org/2007/01/lazy-loading-singletons.html


答案 2

如果您使用的是Apache Commons Lang,那么您可以使用ConcurrentInitializer的变体之一,例如LazyInitializer

例:

ConcurrentInitializer<Foo> lazyInitializer = new LazyInitializer<Foo>() {

        @Override
        protected Foo initialize() throws ConcurrentException {
            return new Foo();
        }
    };

您现在可以安全地获取 Foo(仅初始化一次):

Foo instance = lazyInitializer.get();

如果您使用的是谷歌的番石榴

Supplier<Foo> fooSupplier = Suppliers.memoize(new Supplier<Foo>() {
    public Foo get() {
        return new Foo();
    }
});

然后调用它Foo f = fooSupplier.get();

From Suppliers.memoize javadoc

返回一个供应商,该供应商缓存在第一次调用 get() 期间检索到的实例,并在后续调用 get() 时返回该值。返回的供应商是线程安全的。委托的 get() 方法最多调用一次。如果委托是由先前调用 memoize 创建的实例,则直接返回该实例。


推荐