首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何实现线程安全的延迟初始化?

如何实现线程安全的延迟初始化?
EN

Stack Overflow用户
提问于 2011-11-28 14:57:32
回答 12查看 63.2K关注 0票数 67

实现线程安全的延迟初始化的推荐方法是什么?例如,

代码语言:javascript
复制
// Not thread-safe
public Foo getInstance(){
    if(INSTANCE == null){
        INSTANCE = new Foo();
    }

    return INSTANCE;
}
EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2011-11-28 15:06:11

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

代码语言:javascript
复制
public class Something {
    private Something() {
    }

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

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

看见

成语

这篇关于疯狂鲍勃·李的博文

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

票数 69
EN

Stack Overflow用户

发布于 2014-04-22 09:56:12

如果您使用的是Apache ,那么您可以使用ConcurrentInitializer的一个变体,比如LazyInitializer

示例:

代码语言:javascript
复制
ConcurrentInitializer<Foo> lazyInitializer = new LazyInitializer<Foo>() {

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

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

代码语言:javascript
复制
Foo instance = lazyInitializer.get();

如果你在使用谷歌的番石榴

代码语言:javascript
复制
Supplier<Foo> fooSupplier = Suppliers.memoize(new Supplier<Foo>() {
    public Foo get() {
        return new Foo();
    }
});

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

来自Suppliers.memoize javadoc

返回一个提供者,它缓存在第一次调用get()期间检索的实例,并在随后调用get()时返回该值。返回的供应商是thread-safe.委托的get()方法最多只调用一次()。如果委托是以前调用回忆录所创建的实例,则直接返回它。

票数 70
EN

Stack Overflow用户

发布于 2015-05-14 20:57:12

通过使用AtomicReference作为实例持有人,可以以无锁的方式完成此操作:

代码语言:javascript
复制
// 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;
   }
}

这里的主要缺点是多个线程可以同时实例化两个或多个Foo对象,并且只有一个是幸运的,因此如果实例化需要I/O或另一个共享资源,则此方法可能不适合。

另一方面,这种方法是无锁无等待:如果第一个进入该方法的线程被卡住,它不会影响其他线程的执行。

票数 36
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8297705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档