你会几种单例模式的写法?

概要

单例模式常常会是咱们学习设计模式的第一个模式。在spring框架下,Bean的默认初始化也是单例模式。 单例模式常见的有懒汉模式和饿汉模式。 先来讲说这两个命名由来。 懒汉模式: lazily 饿汉模式: early 感受是音译。。。java

用途

通常状况下,单例对象应该是无状态的,也就是说没有成员变量字段,或者说成员变量不发生变化。 而有状态的对象,每每在系统中是多例存在。不一样的实例拥有不一样的状态。spring

实现方式

饿汉模式

public class Singleton{
    private final static Singleton INSTANCE = new Singleton();
    private Singleton(){}
    public static getInstance(){
        return INSTANCE;
    }
}
复制代码

优势: 线程安全,实现简单,容易理解。 缺点: 空间浪费。在启动的时候就会建立实例。设计模式

饿汉模式&代码块

public class Singleton {
    private static Singleton INSTANCE;
    static {
        INSTANCE = new Singleton();
    }
    private Singleton(){}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
复制代码

这种方式和第一种没有区别。安全

懒汉模式

public class Singleton {
    private static  Singleton INSTANCE;
    private Singleton(){}
    public static Singleton getInstance(){
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}
复制代码

这种方式实现了懒加载,在调用实例对象的时候才构造。可是带来的问题是线程不安全。若是是在多线程环境下,会生成多个实例。多线程

懒汉模式&同步

public class Singleton {
    private static Singleton INSTANCE;
    private Singleton(){}

    public static synchronized Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}
复制代码

要解决线程安全问题,最简单的作法是让方法加个同步。这样一来即可保证线程安全,可是带来的问题是性能损耗。由于其实只有在第一次构造的时候须要同步,之后获取的时候不须要同步的。框架

懒汉模式&double check

public class Singleton {
    private static Singleton INSTANCE;
    private Singleton(){}

    public static Singleton getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        synchronized (Singleton.class) {
            if (INSTANCE == null) {
                INSTANCE = new Singleton();
            }   
        }
        return INSTANCE;
    }
}
复制代码

这种方式就比较完美了。作一个双重检查,保证了在第一次构造实例的时候的线程安全。同时也保证了以后获取实例对象不须要同步。性能

懒汉模式&内部类

public class Singleton {
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}
复制代码

这种方式表面上看和饿汉模式很类似,可是其实也是实现了懒加载。巧妙之处在于利用了内部类启动机制保证了线程安全。我的比较推荐以上两种写法。学习

枚举用法

public enum Singleton {
    INSTANCE;
}
复制代码

坊间还有使用枚举类来实现的例子,虽然也能达到单例的效果,同时也是线程安全。可是我的并不推崇这种用法,缘由在于枚举并非设计来实现单例的,理解起来会让人困惑。spa

相关文章
相关标签/搜索