单例模式是非常好理解的设计模式,但也包含了很多细节。

一、什么是单例模式?

单例模式的定义

1.1、基本定义

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

  • 单例类在内存中只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给其他对象提供访问唯一实例的方法。

    1.2、Java 中单例模式的特点

  • 在一个JVM中,只存在一个实例。

  • 构造器必须是私有的,外部类无法通过调用构造器方法创建该实例。
  • 没有公开的创建对象的方法。
  • 提供一个公开的静态方法获取 JVM 中的唯一实例。

    二、代码实现

    几种实现单例模式的方式

2.1、饿汉式

这个人很饿,所以他管不了那么多了,项目一启动直接创建一个对象塞到 JVM 里。

2.1.1、伪代码

✨ 单例模式 - 图1

2.1.2、代码实现
  1. public class SingleObject {
  2. //第一步:私有化构造函数。
  3. private SingleObject(){}
  4. //第二步:调用私有化的构造函数创建一个对象,并将其赋值给一个私有的静态变量。
  5. private static SingleObject instance = new SingleObject();
  6. //第三步:创建一个静态方法以访问 JVM 中的唯一实例。
  7. //静态方法不属于具体某一个对象,属于类的层次。
  8. public static SingleObject getInstance(){
  9. return instance;
  10. }
  11. //该方法仅是一个普通方法
  12. public void showMessage(){
  13. System.out.println("Hello World!");
  14. }
  15. }

2.2、懒汉式

2.2.1、伪代码

✨ 单例模式 - 图2

2.2.2、代码实现
  1. public class Singleton {
  2. private volatile static Singleton instance = null;
  3. private Singleton(){}
  4. public static Singleton getInstance(){
  5. //先检查实例是否存在,如果不存在才进入下面的同步块
  6. if(instance == null){
  7. //同步块,线程安全的创建实例
  8. synchronized (Singleton.class) {
  9. //再次检查实例是否存在,如果不存在才真正的创建实例
  10. if(instance == null){
  11. instance = new Singleton();
  12. }
  13. }
  14. }
  15. return instance;
  16. }
  17. }

2.3、静态内部类实现单例模式

简单

使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance()的时候,JVM 能够帮我们保证 instance 只被创建一次,并且会保证把赋值给 instance 的内存初始化完毕, 这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这是一个比较完美的单例模式。

  1. public class Singleton {
  2. /* 私有构造方法,防止被实例化 */
  3. private Singleton() {
  4. }
  5. /* 此处使用一个内部类来维护单例 */
  6. private static class SingletonFactory {
  7. private static Singleton instance = new Singleton();
  8. }
  9. /* 获取实例 */
  10. public static Singleton getInstance() {
  11. return SingletonFactory.instance;
  12. }
  13. /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
  14. public Object readResolve() {
  15. return getInstance();
  16. }
  17. }

2.4、通过枚举类的特性实现单例模式

使用枚举来实现单实例控制会更加简洁,而且 JVM 从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。

  1. class Resource{
  2. }
  3. public enum SomeThing {
  4. INSTANCE;
  5. private Resource instance;
  6. SomeThing() {
  7. instance = new Resource();
  8. }
  9. public Resource getInstance() {
  10. return instance;
  11. }
  12. }

参考

1、单例模式 | 菜鸟教程 @RUNOOB
2、设计模式系列 - 单例模式 @敖丙