ITPub博客

首页 > 应用开发 > Java > 一个小的技术细节

一个小的技术细节

Java 作者:喝水会长肉 时间:2021-12-15 17:37:56 0 删除 编辑

在学习过之前的《单例》之后,相信大家一定对单例有了很深的理解,对于双重校验锁的单例实现大家一定都不陌生。

不知道大家有没有关注过一个细节,那就是在双重校验锁中的getInstance方法中,定义了一个局部变量来接收Singleton的单例对象。代码实现如下:


public 
class 
Singleton 
{

    private static volatile Singleton instance = null ;
    private Singleton ( ) {
    }

    public static Singleton getInstance ( ) {
       Singleton temp =instance ; // 定义了一个局部变量
        if ( null == temp ) { //对局部变量进行非空判断
            synchronized ( Singleton .class ) {
               temp = instance ;
                if ( null == temp ) {
                   temp = new Singleton ( ) ; //对局部变量进行赋值
                   instance =temp ; //再将局部变量赋值给单例对象
                }
            }
        }
        return instance ; //返回单例对象
    }
}

以上,便是一个双重校验锁的代码,可以看到,在getInstance方法中定义了一个局部变量temp,在操作过程中都是对这个临时的局部变量进行的操作,最后再赋值给真正的单例对象的。

在很多源码中,也都有类似的做法,如Spring中有以下代码:


private 
static volatile ReactiveAdapterRegistry sharedInstance
;


public static ReactiveAdapterRegistry getSharedInstance ( ) {
//vx耗:mbz_java_panlong 十年开发经验程序员,免费解答,备注“MI”即可

   ReactiveAdapterRegistry registry = sharedInstance ;
    if (registry == null ) {
            synchronized ( ReactiveAdapterRegistry .class ) {
               registry = sharedInstance ;
                if (registry == null ) {
                   registry = new ReactiveAdapterRegistry ( ) ;
                   sharedInstance = registry ;
                }
            }
    }
    return registry ;
}

那么,你知道为什么要这么做吗?

这里其实和volatile有关,我们知道,双重校验锁单例为了避免发生指令重排,一定要使用volatile来定义单例对象。

其实如果大家对于volatile有深入理解的话,这个问题其实不难回答。为了保证共享变量在并发场景下的内存可见性,volatile变量的操作前后都会通过插入内存屏障来进行数据同步,即将线程的本地内存数据同步到主内存(或从主内存将数据同步到线程的本地内存)

而这个过程其实是有很大的损耗的,我们可以想办法降低对于volatile变量的访问次数,那就是通过定义局部变量的方式。

因为局部变量并不是共享的,所以不需要进行线程本地内存和主存之间的数据同步,操作效率就会很高。

所以,使用局部变量,是一种性能提升的方式,可以减少主存与线程内存的拷贝次数。

(全文完)



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70010294/viewspace-2847955/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-19

  • 博文量
    199
  • 访问量
    86387