设计模式之单例模式

一、单例模式的特点:

  • 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例

二、常见的几种单例模式

1、饿汉式,静态常量

  • 在类装载时就完成类的初始化,没有达到lazy loading的效果,如果从始至终没有使用过这个类,可能造成内存浪费。
  • 避免了多线程同步问题
public class Singleton01 {

    private final static Singleton01 instance = new Singleton01();

    //构造器私有化(防止new)
    private Singleton01() {
    }

    public static Singleton01 getInstance() {
        return instance;
    }
} 

2、饿汉式,静态代码块

  • 将类实例化的过程放在了静态代码块中,也是在类装载的时候就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的
public class Singleton02 {

    private static Singleton02 instance;

    //在静态代码块中创建单例对象
    static {
        instance = new Singleton02();
    }

    private Singleton02() {
    }

    public static Singleton02 getInstance() {
        return instance;
    }
}  

3、懒汉式,线程不安全(不推荐使用)

  • 只能在单线程下使用。
  • 多线程下,一个线程进入了if(singleton==null) 判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。
public class Singleton03 {

    //声明类的唯一实例
    private static Singleton03 instance;

    //造方法私有化,不允许外部直接创建对象
    private Singleton03() {
    }

    //当使用到getInstance()方法时,才去创建该对象
    public static Singleton03 getInstance() {
        if (instance == null) {
            instance = new Singleton03();
        }
        return instance;
    }
}  

4、懒汉式,线程安全(不推荐使用)

  • 问题:效率太低,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步
public class Singleton04 {

    //声明类的唯一实例
    private static Singleton04 instance;

    //造方法私有化,不允许外部直接创建对象
    private Singleton04() {
    }

    //当使用到getInstance()方法时,才去创建该对象
    public synchronized static Singleton04 getInstance() {
        if (instance == null) {
            instance = new Singleton04();
        }
        return instance;
    }

} 

5、DCL双重检锁机制(Double Check Lock)【推荐使用】

  • 两次检查instance == null,一次是在同步块外,一次是在同步块内。第一次检查instance不为null,那么就不需要执行下面的加锁和初始化操作。可以大幅降低synchronized带来的性能开销。
  • 使用volatile禁止指令重排序,对volatile变量的写操作都先行发生于后面对这个变量的读操作
class Singleton05 {

    private static volatile Singleton05 instance;

    private Singleton05() {
        System.out.println(Thread.currentThread().getName() + " 构造方法SingletonDemo");
    }

    //解决线程安全问题,解决懒加载问题,同时保证了效率
    public static Singleton05 getInstance() {
        if (instance == null) {
            synchronized (Singleton05.class) {
                if (instance == null) {
                    instance = new Singleton05();
                }
            }
        }
        return instance;
    }
} 

6、静态内部类(推荐使用)

  • 采用了类装载的机制来保证初始化实例时只有一个线程。
  • Singleton07类装载时,不会导致静态内部类被装载,当调用getInstance()方法时,静态内部类会装载,而且只装载一次,并且是线程安全的
  • 避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
public class Singleton06 {

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

    //构造器私有化
    private Singleton06() {
    }

    public static final Singleton06 getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

7、枚举(推荐使用)

  • 不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton07 {
    INSTANCE;
}  

总结:

一般情况下直接使用饿汉式就好了,
如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,
如果涉及到反序列化创建对象时会试着使用枚举的方式来实现单例

三、单例模式的使用场景:

需要频繁创建和销毁的对象

创建对象耗时过多或耗费资源过多,但又经常用到的对象

频繁访问数据库或文件的对象(比如Hibernate的SessionFactory

四:实际应用

JDK中java.lang.Runtime 使用单例模式的饿汉式

  

有道词典
public static v ...
详细X
 
instance  ['ɪnst(ə)ns]  详细X
基本翻译
n. 实例;情况;建议
vt. 举...为例
网络释义
INSTANCE: 实例
Instance variable: 实例变量

 

posted @ 2019-06-27 09:44  与君共舞  阅读(241)  评论(0编辑  收藏  举报