美文网首页
关于延迟初始化

关于延迟初始化

作者: Lcap | 来源:发表于2019-10-30 20:16 被阅读0次

最近常在代码中见到延迟初始化,想和大家聊聊这个小话题。最简单的延迟初始化很容易想,提起键盘我就能敲出来啊:

public class DelayInitializationWithSingleThread {
    private static Object foo;
    
    public static Object getInstance() {
        if(foo == null)
            this.foo = new Object();
        return this.foo;
    }
}

这个延迟初始化,单线程下很完美,多线程下岂不是要乱套!那简单,那我在方法上加一个同步操作好了:

public class DelayInitializationWithMultiThread {
    private static Object foo;
    
    public synchronized static Object getInstance() {
        if(foo == null)
            this.foo = new Object();
        return this.foo;
    }
}

但是加锁需要上下文切换,是个很耗系统资源的操作,每次调用getInstance()都要执行一次上下文切换,有些没必要。我只需要在第一次初始化的时候进行加锁就好了啊,这就是著名的DCL(Double Check Lock):

public class DelayInitializationWithDCL {
    private static Object foo;
    
    public synchronized static Object getInstance() {
        if(foo == null) {
            synchronized (Test.class) {
                if(foo == null)
                    this.foo = new Object();
            }
        } 
        return this.foo;
    }
}

看起来很不错。
等一下,还记得JVM的可见性吗?每个线程的变量都是在各自线程的缓存中,各自的工作变量相互不可见,必须等到JVM将其刷到公用的主存里才能对其他线程可见。也就是说A线程初始化foo后,B线程不一定能看得到,在不知道的情况下,那B会再执行一遍初始化,C线程也不一定看得见,他继续。。。这还只是个简单的示例代码,要是工作代码执行一些复杂的初始化的话,那不是可能造成对象失效或者脏数据?好吧我不敢再往下想了,赶紧给变量foo加上消除线程缓存作用的volatile关键字。

public class DelayInitializationWithVolatiledDCL {
    private volatile static Object foo;
    
    public synchronized static Object getInstance() {
        if(foo == null) {
            synchronized (Test.class) {
                if(foo == null)
                    this.foo = new Object();
            }
        }
        return this.foo;
    }
}

呼呼。。这下终于完成了,看着很完美。但是啊,有些复杂,万一哪天我头脑发热,忘记加volatile咋办呢。好吧,为了有更好的方案,继续改造:

public class DelayInitializationWithInitalizationPlaceHolder {
    private static class ResourceHolder {
        public static Object foo = new Object(); 
    }
    public synchronized Object getInstance() {
        return ResourceHolder.foo;
    }
}

当getInstance()第一次被调用时,JVM会加载ResourceHolder类,并将其静态变量初始化,以后再次调用就能直接获取到初始化的foo了,不需要加锁,不需要volatile,简直太棒了,完美!

相关文章

  • 关于延迟初始化

    最近常在代码中见到延迟初始化,想和大家聊聊这个小话题。最简单的延迟初始化很容易想,提起键盘我就能敲出来啊: 这个延...

  • Java对象延迟初始化的实现

    一、什么是延迟初始化? 在Java多线程程序中,有时候需要采用延迟初始化来降低初始化类和创建对象的开销。延迟初始化...

  • app启动加速

    1.在 Application 中做初始化:利用异步延迟初始化,或者延迟到 Activity 中初始化。 2.在 ...

  • 更多DI的知识

    3.3.1 延迟初始化Bean延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初...

  • Kotlin延迟初始化lateinit和by lazy的区别

    延迟初始化为什么要进行延迟初始化?kotlin中的属性在声明的同时必须初始化,否则会报错 private var ...

  • Kotlin 入门中

    1、定义静态的成员变量,然后延迟初始化 lateinit:延迟初始化属性companion:伴生对象 2、swit...

  • 销毁Spring Bean: 销毁Bean的基本操作有哪些?

    Spring 源码解读分析中上一篇主要介绍关于Bean的初始化以及延迟初始化,接下来分析Bean的销毁阶段-和Be...

  • Kotlin之延迟初始化和密封类

    1、延迟初始化 先看个实例看下延迟初始化的应用场景: 我们声明了成员变量messageAdapter,它是在onC...

  • 线程安全的延迟初始化:线程安全的创建单例

    2019-12-31 为什么要进行字段的延迟初始化? 因为对字段的延迟初始化可以降低初始化类或创建实例的开销。 不...

  • kotlin中lateinit 和by lazy

    一、 lateinit 延迟初始化 二、by lazy惰性初始化(区别于lateinit)

网友评论

      本文标题:关于延迟初始化

      本文链接:https://www.haomeiwen.com/subject/ussavctx.html