设计模式之单例模式(创建型)

前言

本博客介绍一种创建型模式:单例模式
这是一种比较容易理解的设计模式,可以理解为创建对象的一种很好的做法。可以尽量避免创建过多的对象,给JVM造成很大的负载。

应用场景

单例模式的一些应用场景:
1、比如数据连接类,这是需要经常调用的
2、网站访问量统计的服务类,需要多次调用
3、导出导入Excel表,一些业务复杂的系统需要多次调用
...

总结起来就是需要经常调用的通用类,我们可以用单例模式进行很好的设计。

编程思想

单例模式涉及了两种重要的编程思想:懒加载思想和缓存思想

缓存思想:

    private static Singleton instance = null;//先放内存缓存
   
    public static Singleton getInstance() {
        if (instance == null) {//内存加载不到,创建对象
            instance = new Singleton();
        }
        return instance;//内存缓存有,直接调用
    }

懒加载思想:
下面例子就是懒加载的简单应用,创建一个对象都是需要用的时候实例,尽量不要在加载类的时候就实例了,这种方法可以很好的避免给JVM增加负载。这是一种很好的编程习惯。

public static Singleton getInstance() {
        if (instance == null) {//对象需要用时才实例
            instance = new Singleton();
        }
        return instance;
    }

单例模式实例

下面介绍几种常用的单例模式实例

1、懒汉模式
这是一种线程不安全,懒加载的方式

public class Singleton {
    private static Singleton instance;
    //定义private构造函数,使类不可以被实例
    private Singleton (){}

    /**
     * 懒汉模式,线程不安全,懒加载
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

上面例子线程不安全,要线程安全可以加个同步锁,不过加了同步锁性能又不好了,加载慢

public class Singleton {
    private static Singleton instance;
    //定义private构造函数,使类不可以被实例
    private Singleton (){}

    /**
     * 懒汉模式,线程安全,懒加载
     * @return
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2、饿汉模式
下面介绍一下单例模式的另外一种实现方式,饿汉模式
其实现原理就是在类内部全局new一个对象,利用Java虚拟机的类加载机制,保证了线程安全,不过很明显,一创建了,就实例了单例类,会给JVM增加负载

public class Singleton {
    //定义private构造函数,使类不可以被实例
    private Singleton (){}


    //加载类的时候,利用JVM的类加载机制创建对象,保证了线程安全,但是效率不好
    private static Singleton instance = new Singleton();

    /**
     * 饿汉模式,线程安全,非懒加载
     * @return
     */
    public static Singleton getInstance() {
        return instance;
    }
}

3、双检锁/双重校验锁(DCL,即 double-checked locking)
下面介绍一种双检锁的实现方式,这种方式看起来稍稍比较复杂了点,不过可以实现线程安全,同时双检锁的方式可以保证性能比较高

public class Singleton {
 
    //定义private构造函数,使类不可以被实例
    private Singleton (){}

    private volatile static Singleton instance;

    /**
     * 双检锁/双重校验锁(DCL,即 double-checked locking)线程安全,懒加载
     * @return
     */
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

4、登记式/内部类
下面用内部类的方式来实现单例模式,这种方式可以和饿汉模式来对比一下
这种方式和刚才介绍的饿汉模式类似,不过区别就是做到了懒加载,我们可以分析例子。方法就是在单例类里加个内部类,这样做就不会像饿汉模式一样,单例类一加载就实例对象。当调用getInstance方法的时候,才会调用,创建对象。这样就做到了懒加载,同时也是利用JVM保证了线程安全

public class Singleton {
   
    //定义private构造函数,使类不可以被实例
    private Singleton (){}

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

    /**
     * 登记式/静态内部类,线程安全,懒加载
     * @return
     */
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

5、枚举模式
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。

/**
     * 枚举方式
     */
    public enum Singleton {
        INSTANCE;
        public void whateverMethod() {
        }
    }

猜你喜欢

转载自www.cnblogs.com/mzq123/p/9064683.html