设计模式之单例模式

Spring Wu 396 2018-03-10

单例模式

  • 只有一个实例;
  • 必须由自己创建自己的唯一实例;
  • 必须提供一个公共方法供其他对象使用自己的实例。

饿汉式单例模式

饿汉式顾名思义,不管你需不需要,只要你引用了该类,就会创建对象的实例。

 *  经典的饿汉式单例模式
 * [@author](https://my.oschina.net/arthor) wushuaiping
 * [@date](https://my.oschina.net/u/2504391) 2018/3/10 上午9:17
 */
public class Singleton {

    private static Singleton singleton = new Singleton();

    private Singleton(){}

    public static Singleton getSingleton(){
        return singleton;
    }
}

懒汉式单例模式

but .. 上述写法无法做到lazy load(延迟加载),lazy load意思就是我在需要的时候才去创建实例。于是我们可以使用如下写法:

/**
 *  保证lazy load的单例模式,懒汉式单例
 * @author wushuaiping
 * @date 2018/3/10 上午9:17
 */
public class Singleton {

    private static Singleton singleton = null;

    private Singleton(){}

    public static Singleton getSingleton(){
        if (singleton == null){
            singleton = new Singleton();
            return singleton;
        }
    }
}

线程安全的懒汉单例模式

but.. 上述写法无法保证线程安全性,如果在单线程环境下,上述写法,就不会出现创建重复的对象的情况,但是如果在多线程情况下,有多条线程同时调用了getSingleton()方法,那么极有可能创建出多余且重复的对象。那么此时想到的解决方案是对代码块或者方法加入同步锁,保证线程安全,于是我们可以这样写

/**
 *  保证lazy load并且保证线程安全的单例模式,懒汉式单例
 * @author wushuaiping
 * @date 2018/3/10 上午9:17
 */
public class Singleton {

    private static Singleton singleton = null;

    private Singleton(){}

    public static synchronized Singleton getSingleton(){
        if (singleton == null){
            singleton = new Singleton();
            return singleton;
        }
    }
}

/**
 *  保证lazy load并且保证线程安全的单例模式,懒汉式单例
 * @author wushuaiping
 * @date 2018/3/10 上午9:17
 */
public class Singleton {

    private static Singleton singleton = null;

    private Singleton(){}

    public static Singleton getSingleton(){
        synchronized(Singleton.class){
            if (singleton == null){
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

即保证线程安全也保证效率的懒汉式单例

but.. 通过上述写法,我们虽然保证了线程安全,但是我们代码的效率却降低了,why? 因为我们使用了synchronized啊,当一个线程进入synchronized修饰的方法或者代码块后,其他线程必须在后面排队,导致了代码的效率的降低,于是我们可以使用Duoble-check来继续优化代码:

/**
 *  保证lazy load并且保证线程安全还兼顾了效率的单例模式,懒汉式单例
 * @author wushuaiping
 * @date 2018/3/10 上午9:17
 */
public class Singleton {

    private static Singleton singleton = null;

    private Singleton(){}

    public static Singleton getSingleton(){
        if (singleton == null){
            synchronized(Singleton.class){
                if (singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

该方式为什么能保证效率呢?我们写懒汉式单例的原因是,我们不想要在JVM加载类的时候就创建对象,而是在我们需要该对象的时候才去创建对象,所以我们想到了懒汉式单例模式,而正是因为懒汉式单例模式的特性,通过Duoble-check,每个线程经过第一个if(singleton == null)的时候,基本都会因为之前已经创建过了该对象,而直接返回,所以,该方式效率得到了保证。

实现单例的方式有很多种。我只是列出了几种常见的单例模式,当然最常见的还是枚举。如果各位有更好的单例模式请指教,本文只做个人笔记记录,欢迎各位看官批评。 O(∩_∩)O谢谢


# 设计模式