实现单例模式需要考量的几个点

单例模式是一个老生常谈的话题了,如何实现呢?我们这里不再赘述,我们这里梳理一下思路,看看设计一个单例模式需要考虑的问题。


1,延迟加载

new操作放在方法内部,不要作为类的静态成员变量暴露给调用者。


2,只实例化一次

实例化之前先判断是否为null。


3,线程安全

有多种思路:synchronized关键字,内部类等。

synchronized关键字其实就是加锁,这是jvm给我们提供的一种线程安全机制。

内部类是使用到了jvm类加载机制,jvm能够保证一个类在加载的时候是线程安全的。


4,规避反射调用

反射机制增强了java的动态性,但是也会带来一些问题。比如我们这里要讨论的,反射机制破坏了单例模式,为什么呢?因为反射机制可以绕过java类的访问权限,调用java类的私有构造方法,生成类对象。

兵来将挡水来土掩。要解决这个问题,我们最常用的方式是拋异常。


好了,只要掌握了这几个要点,然后结合自己的业务场景,相信你也可以写出自己的单例类了。






下面我们看一个实例:Logger实例。

我们在实际开发中,打印日志都会这样来写:

private static final Logger logger = LoggerFactory.getLogger(Xxx.class);

Slf4j日志框架在生成logger实例时,使用了单例模式,当然,还有其他设计模式,比如工厂模式和门面模式等。

我们看一下源码,源码在LoggerFactory.class中,最终调用方法getLoggerFactory(),该方法源码如下:


public static ILoggerFactory getILoggerFactory(){

    if (INITIALIZATION_STATE == 0){

        Class var0 = LoggerFactory.class;

        synchronized(LoggerFactory.class){

            if (INITIALIZATION_STATE == 0){

                INITIALIZATION_STATE == 1;

                performInitialization();

            }

        }

    }

}





performInitialization()方法最终会调用StaticLoggerBinder.getSingleton(),该方法源码如下:


// Logger实例没有延迟加载,而是初始化StaticLoggerBinder的时候就加载了

private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder();3


public static StaticLoggerBinder getSingleton(){

    return SINGLETON;

}

你可能感兴趣的:(实现单例模式需要考量的几个点)