2-单例模式 - 创建型模式

本文深入探讨了单例模式的设计原则,包括其唯一实例的特点、构造函数的私有化及实例获取方法。通过多个实例代码,详细讲解了饿汉式、懒汉式、内部静态类及枚举类等不同实现方式,帮助读者全面理解单例模式。


参考:设计模式之禅,https://www.runoob.com/

1.最简单的 例子

在这里插入图片描述

public class SingleObject {
    private static SingleObject instance = new SingleObject();

    private SingleObject() {

    }

    public static SingleObject getInstance() {
        return instance;
    }

    public void showMessage() {
        System.out.println(instance);
    }
}
public class SingletonPatternDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            SingleObject instance = SingleObject.getInstance();
            instance.showMessage();
        }
    }
}

输出结果是一样的,表明是同个对象。

com.freedom.pattern.singleton.SingleObject@47089e5f
com.freedom.pattern.singleton.SingleObject@47089e5f
com.freedom.pattern.singleton.SingleObject@47089e5f

2. 单例模式特点

  • 只有一个实例;
  • 构造函数必须私有,即其他对象不能通过new创建;
  • 自身必须提供获得实例的方法。

3. 延伸阅读

  • https://refactoringguru.cn/design-patterns/singleton
  • https://www.runoob.com/design-pattern/singleton-pattern.html
  • https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/singleton.html

4. 几种单例写法

4.1 饿汉式1

/**
 * 饿汉式
 * <p>
 * 类加载的时候就实例化,保证线程安全, 简单实用。 缺点:如果不用也实例化,占内存。
 * </p>
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton01 {

  private static Singleton01 INSTANCE = new Singleton01();

  private Singleton01() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  public static Singleton01 getInstance() {
    return INSTANCE;
  }

  public static void main(String[] args) {
    Singleton01 instance = Singleton01.getInstance();
    instance.doSomething();

    Singleton01 instance2 = Singleton01.getInstance();
    System.out.println(instance == instance2);
  }

}

4.2 饿汉式2

/**
 * 饿汉式,跟Singleton01一样
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton02 {

  private static Singleton02 INSTANCE;

  static {
    INSTANCE = new Singleton02();
  }

  private Singleton02() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  public static Singleton02 getInstance() {
    return INSTANCE;
  }

  public static void main(String[] args) {
    Singleton02 instance = Singleton02.getInstance();
    instance.doSomething();

    Singleton02 instance2 = Singleton02.getInstance();
    System.out.println(instance == instance2);
  }

}

4.3 懒汉1

/**
 * 懒汉式,实现了按需加载,但是线程不安全
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton03 {

  private static Singleton03 INSTANCE;

  private Singleton03() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  public static Singleton03 getInstance() {
    if (INSTANCE == null) {
      // 模拟创建对象比较慢
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      INSTANCE = new Singleton03();
    }
    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton03.getInstance().hashCode())).start();
    }
  }

}

4.4 懒汉2

/**
 * 懒汉式,实现了按需加载,线程是安全了,但是获得实例对象的操作都是
 * 串行化,影响性能
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton04 {

  private static Singleton04 INSTANCE;

  private Singleton04() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  /**
   * synchronize修饰静态方法,它的锁就是当前的类对象,相当于synchronized(Singleton04.class)
   */
  public static synchronized Singleton04 getInstance() {
    if (INSTANCE == null) {
      // 模拟创建对象比较慢
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      INSTANCE = new Singleton04();
    }
    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton04.getInstance().hashCode())).start();
    }
  }

}

4.5 懒汉3

/**
 * 懒汉式,实现了按需加载,获得实例对象的操作不都是串行化,
 * 提升性能,但是线程不安全,编译优化有可能让还未初始化的INSTANCE返回,
 * 其他线程因此拿到实例调用报空指针异常
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton05 {

  private static Singleton05 INSTANCE;

  private Singleton05() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  public static Singleton05 getInstance() {
    if (INSTANCE == null) {
      synchronized (Singleton05.class) {
        if (INSTANCE == null) {
          // 模拟创建对象比较慢
          try {
            Thread.sleep(10);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          INSTANCE = new Singleton05();
        }
      }
    }
    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton05.getInstance().hashCode())).start();
    }
  }

}

4.6 懒汉4

/**
 * 懒汉式,实现了按需加载,获得实例对象的操作不都是串行化,
 * 提升性能,volatile保证变量可见性。比较理想的写法。
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton06 {

  private static volatile Singleton06 INSTANCE;

  private Singleton06() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  public static Singleton06 getInstance() {
    // 双重检查
    if (INSTANCE == null) {
      synchronized (Singleton06.class) {
        if (INSTANCE == null) {
          // 模拟创建对象比较慢
          try {
            Thread.sleep(10);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          INSTANCE = new Singleton06();
        }
      }
    }
    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton06.getInstance().hashCode())).start();
    }
  }

}

4.7 内部静态类

/**
 * 内部静态类方式,JVM保证单例。加载外部类时不加载器静态内部类
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public class Singleton07 {

  private Singleton07() {
  }

  public void doSomething() {
    System.out.println("Do something");
  }

  private static class InnerHolder{
    private static final Singleton07 INSTANCE = new Singleton07();
  }

  public static Singleton07 getInstance() {
    return InnerHolder.INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton07.getInstance().hashCode())).start();
    }
  }

}

4.8 枚举类实现

/**
 * 枚举实现方式:线程安全,不被反序列化
 *
 * @author tobebetter9527
 * @create 2021/07/24 11:08
 */
public enum Singleton08 {

  INSTANCE;

  public void doSomething() {
    System.out.println("Do something");
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(() -> System.out.println(Singleton08.INSTANCE.hashCode())).start();
    }
  }

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值