设计模式——单例模式的几种写法

来源:互联网 发布:3055 知乎 编辑:程序博客网 时间:2024/05/16 15:08

一、单例模式


单例模式是一种创建型的模式,指某个类采用单例模式后,在这个类被创建后,只产生一个实例以供外部访问,且提供一个全局的访问点。


单例模式在开发中具有相当大的重要性,并且代码实现相对简洁。所以其是为数不多的在面试中会被问到且要求手撸代码的设计模式哦:)

 

二、几种单例的写法及比较


1. 饱汉模式

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class Singleton1 {    private static Singleton1 instance;    public static Singleton1 getInstance() {        if (instance == null) {            instance = new Singleton1();        }        return instance;    }}

这种模式下,可以做到延迟化加载,但是在多线程模式下会产生多个实例,可不就是很“饱”么XD?此模式非线程安全,不推荐使用

 

2. 饱汉模式改进

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class Singleton2 {    private static Singleton2 instance;    public static synchronized Singleton2 getInstance() {        if (instance == null) {            instance = new Singleton2();        }        return instance;    }}

此模式将getInstance方法进行同步,看似解决了线程的安全问题,但是同步粒度太大,效率十分低下,不建议使用

 

3. 饿汉模式

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class Singleton3 {    private static final Singleton3 instance = new Singleton3();    public static Singleton3 getInstance() {        return instance;    }}

此模式在类加载时就实例化对象,做到了线程安全,但是instance在类装载时就实例化。但是想象一种场景,如果实例化instance非常得消耗资源,或者实例的使用并非那么频繁,我们想让实例延迟加载,在我们需要使用的时候才被实例化,那这种时候此模式就很不合理了。这是一种十分耗费资源的粗暴的模式,不建议使用

 

4. 双重检查锁(Double-checked Locking)

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class Singleton4 {    private volatile static Singleton4 instance;    public static Singleton4 getInstance() {        if (instance == null) {            synchronized (Singleton4.class) {                if (instance == null)                    instance = new Singleton4();            }        }        return instance;    }}

此模式将与第二种单例的模式有点类似,减少了同步的开销。相对来说是一个合理的单例写法,但是此模式也并不是完美的。我们知道类的实例化并不是一个简单的操作,内部其实主要包含了以下步骤:分配内存,初始化,实例指向内存。那么当我们在进入第二个if (instance == null)时,开始为实例分配内存,此时其他线程执行到第一个if (instance == null)时,instance并不为空,于是此线程将直接返回instance,然而此时的instance因为没有实例化结束,返回的实例并不是完整的。这就会导致错误的发生,这种模式需要慎用

 

5. 静态内部类

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class InnerSingleton {    // 静态内部类    private static class GetInstance {        private static final InnerSingleton INSTANCE = new InnerSingleton();    }    public static final InnerSingleton getInstance() {        return GetInstance.INSTANCE;    }}

此模式起到了延时加载的作用,只有显示调用getInstance方法时,才会显示装载GetInstance类,从而实例化INSTANCE。此方法线程安全,推荐使用

 

6. 枚举

package designpatterns.singleton;/** * Created by Olive on 2017/12/8. */public class Animal {}public enum AnimalSingleton {    INSTANCE;    public Animal getAnimalSingleton(){        final Animal animal = new Animal();        return animal;    }}

要生成Animal的单例可以调用AnimalSingleton.INSTANCE. getAnimalSingleton。这种模式也是一种线程安全的单例实现,但是枚举在开发中用的并不多,所以一般大概也许很少人会采用这种模式吧。