设计模式-单例模式

这次主要记录下单例模式的学习过程


一、什么是单例模式

  • 单例模式(Singleton Pattern):保证一个类仅有一个实例,并提供一个访问它的全局访问点
  • 可划分为 饿汉式懒汉式 两种
  • 特点:
    • 单例类确保自己只有一个实例
    • 单例类必须自己创建自己的实例
    • 单例类必须为其他对象提供唯一的实例
  • 优点:
    • 在内存里只有一个实例,减少了内存的开销
    • 避免了对于资源的多重占用 (如读写操作)
    • 由于类控制了实例化过程,所以类可以灵活地更改实例化过程
  • 缺点:
    • 由于不是抽象的,所以扩展性较差
    • 职责过重,在一定程度上,违背了单一职责原则

二、单例模式—饿汉式

  • 饿汉式,顾名思义,该单例类十分饿,因此需要在类一加载的时候就创建实例,是 线程安全
  • 不管使不使用,只要类一加载就会创建实例,因此如果不使用的话,会浪费内存空间,但在需要用的时候,可以直接返回已经创建好的实例,节省了时间消耗
  • 是典型的 空间换时间 的示例

饿汉式类

/**
 * @Title: HungrySingletonPattern.java
 * @Description: 饿汉式类
 * @Author: xj
 * @Date: 2018/10/20 10:04
 */
public class HungrySingletonPattern {

    private static HungrySingletonPattern hungrySingletonPattern = new HungrySingletonPattern();
	// 私有化构造函数,防止通过new的方式来创建实例
    private HungrySingletonPattern() {
        System.out.println("饿汉式 ---> 调用构造方法");
    }
	// 提供一个公共的,静态的,返回本类实例的方法
    public static HungrySingletonPattern getInstance() {
        System.out.println("饿汉式 ---> 调用静态方法返回实例");
        return hungrySingletonPattern;
    }
}

测试类

/**
 * @Title: Test.java
 * @Description: 测试类
 * @Author: xj
 * @Date: 2018/10/20 10:16
 */
public class Test {

    public static void main(String[] args) {
        // 饿汉式
        System.out.println("=============== 单例模式: 饿汉式 ===============");
        HungrySingletonPattern h1 = HungrySingletonPattern.getInstance();
        HungrySingletonPattern h2 = HungrySingletonPattern.getInstance();
        if (h1 == h2) {
            System.out.println("=============== h1与h2为同一实例 ===============");
        }
    }
}

输出结果
在这里插入图片描述


三、单例模式—懒汉式

  • 懒汉式,顾名思义,该单例类十分懒,因此在需要用到实例的时候才会去创建实例,是 线程不安全
  • 只要不使用,就不会创建实例,可以节省内存空间,但在需要用的时候,需要创建实例,增加了时间消耗
  • 是典型的 时间换空间 的示例

懒汉式类

/**
 * @Title: LazySingletonPattern.java
 * @Description: 懒汉式类
 * @Author: xj
 * @Date: 2018/10/20 10:03
 */
public class LazySingletonPattern {
    // volatile关键字用于防止JVM进行指令重排
    private volatile static LazySingletonPattern lazySingletonPattern;
    // 私有化构造函数,防止通过new的方式来创建实例
    private LazySingletonPattern() {
        System.out.println("懒汉式 ---> 调用构造方法");
    }
    // 提供一个公共的,静态的,返回本类实例的方法
    public static LazySingletonPattern getInstance() {
        if (null == lazySingletonPattern) {
            synchronized (LazySingletonPattern.class) {
                if (null == lazySingletonPattern) {
                    System.out.println("懒汉式 ---> 创建实例");
                    lazySingletonPattern = new LazySingletonPattern();
                } else {
                    System.out.println("懒汉式 ---> 实例已被创建");
                }
            }
        }
        System.out.println("懒汉式 ---> 调用静态方法返回实例");
        return lazySingletonPattern;
    }
}

测试类

/**
 * @Title: Test.java
 * @Description: 测试类
 * @Author: xj
 * @Date: 2018/10/20 10:16
 */
public class Test {

    public static void main(String[] args) {
        // 懒汉式
        System.out.println("=============== 单例模式: 懒汉式 ===============");
        LazySingletonPattern l1 = LazySingletonPattern.getInstance();
        LazySingletonPattern l2 = LazySingletonPattern.getInstance();
        if (l1 == l2) {
            System.out.println("=============== l1与l2为同一实例 ===============");
        }
    }
}

输出结果
在这里插入图片描述


  • 懒汉式中,声明静态成员时,使用了 volatile 关键字,其提供了 “内存屏障” 的方式来防止指令被重排序,为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序
  • 此外,还使用了 Double Check Locking (双重锁定) + synchronized 关键字,来确保操作的原子性

四、参考链接

posted @ 2018-10-20 15:09  GeneXu  阅读(54)  评论(0)    收藏  举报