Singleton单例模式

应用场景

只需要一个实例

  • 如各种Mgr (manager管理类)
  • 如各种Factory

饿汉式

  • 类加载到内存后,就实例化一个单例,JVM保证线程安全
  • 简单实用,推荐使用
  • 缺点:不管是否用到,类装载时就完成实例化
/**
 *饿汉式:
 *
 * 类加载到内存后,就实例化一个单例,JVM保证线程安全
 * 简单实用,推荐使用
 * 缺点:不管是否用到,类装载时就完成实例化
 */
public class Mgr01 {

    private static final Mgr01 INSTANCE = new Mgr01();

    // 构造方法私有化
    private Mgr01() {};

    // 暴露给外部调用,返回同一个对象,保证单例
    public static Mgr01 getInstance() {
        return INSTANCE;
    }

    // 其它方法
    public void m(){};

}

懒汉式

写法1

优点:按需初始化
缺点:多线程时可能会创建多个实例

/**
 * lazy loading
 * 也称懒汉式
 * 虽然达到了按需初始化的目的,但多线程时会有一些问题
 */
public class Mgr02 {

    private static Mgr02 INSTANCE;

    // 构造方法私有化
    private Mgr02() {};

    // 该方法被调用时才创建实例
    public static Mgr02 getInstance() {
        // 此时若正好有多个线程进入判断,那么会new出多个对象
        if ( INSTANCE == null) {   
            INSTANCE = new Mgr02();
        }
        return INSTANCE;
    }

    // 其它方法
    public void m(){};

}

写法2

  • 加锁改进后解决多线程问题,但效率降低
/**
 * 懒汉式改进
 *
 * 可以通过synchronized解决多线程问题,但也带来效率下降
 */
public class Mgr03 {

    private static volatile Mgr03 INSTANCE;

    // 构造方法私有化
    private Mgr03() {};

    // 加锁
    public static synchronized Mgr03 getInstance() {
        if ( INSTANCE == null) {
            INSTANCE = new Mgr03();
        }
        return INSTANCE;
    }

    // 其它方法
    public void m(){};

}

写法3

  • 若想再进一步提高效率:判空后再加锁,双重检查锁(double-checked locking)
public class Mgr04 {

    private static volatile Mgr04 INSTANCE;

    // 构造方法私有化
    private Mgr04() {};

    // 该方法被调用时才创建实例
    public static Mgr04 getInstance() {
        if ( INSTANCE == null) {
            // 双重检查   如果是单次检查,仍有可能有多个线程进入if判断
            synchronized (Mgr04.class) {
                if ( INSTANCE == null ) {
                    INSTANCE = new Mgr04();
                }
            }
        }
        return INSTANCE;
    }

    // 其它方法
    public void m(){};

}

写法4

  • 静态内部类方式。懒加载,JVM保证线程安全。
    Mgr05类被加载时,内部类Mgr05Holder不会被加载,当getInstance()方法被调用时Mgr05Holder才会被加载,从而实现了懒加载
/**
 * 静态内部类方式
 * JVM保证单例
 * 加载外部类时不会加载内部类,这样可以实现懒加载
 */
public class Mgr05 {

    // 构造方法私有化
    private Mgr05() {};
    // 静态内部类
    private static class Mgr05Holder {
        private static final Mgr05 INSTANCE = new Mgr05();
    }

    public static Mgr05 getInstance() {
        return Mgr05Holder.INSTANCE;
    }

    // 其它方法
    public void m(){};

}

写法5

  • 枚举单例,语法上最完美
/**
 * 不仅可以解决线程同步,还可以防止反序列化
 */
public enum Mgr06 {

    INSTANCE;

    // 其它方法
    public void m(){};

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、定义 确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例 2、特点 单例类只能有一个实例。 单例类...
    冰镇柠檬_tree阅读 1,865评论 0 0
  • Singleton单例模式根据产生时机不同,可分为如下三类:(1)懒汉式(2)饿汉式(3)登记式在Java设计模式...
    莫问以阅读 2,593评论 0 1
  • 动机 有些情况下,一个类只能有一个实例是很重要的。比如说,在操作系统中只能有一个窗口管理器的(文件系统或打印机程序...
    holysu阅读 5,020评论 0 0
  • 搬运自大神博客单例模式(Singleton)及其C++实现 单例模式,在GOF的《设计模式:可复用面向对象软件的基...
    leon4ever阅读 5,837评论 0 1
  • 我撒过很多谎, 比如, 梦中哭泣只因噩梦缠身; 雪登黄山只是情怀使然。 我对别人说得风轻云淡 但是,我知道, 噩梦...
    山野啊阅读 2,755评论 3 8