打通设计模式任督二脉 -- 单例模式

简介: 深度解析单例模式

@[toc]

前言:想必想了解设计模式的各位都是走开发路线的吧,那么既然是走开发路线的,那么设计模式可是一定要好好学哦。因为它是一种思想,将会贯彻到你的开发过程,同时如果你使用的得当的话,那么你的项目将会十分的流畅且亮点丰富。当然这也是开始学之前的一些废话。总之,脚踏实地好好学。

在这里插入图片描述

1、设计模式介绍

我们得先从设计模式的定义出发。哈哈,不知道你们学习东西的流程是什么。反正我学习的一个流程是先要知道这个东西是什么,然后再知道为什么要学习这个东西,然后就是怎样使用这个东西了。这个是学习东西的一个方法和套路,我们需要总结出自己的一个学习新事物的套路来,这样才能事半功倍。

  • 什么是设计模式?

那么什么是设计模式呢?

  1. 官方的定义:软件设计模式,又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。
  2. 说到底,它就是面向对象设计原则的实际运用思想和经验总结,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。

通过上述的定义的描述,大家肯定都对设计模式有了一定的初步的印象了,但是要进行深刻理解的话,这样还是不够的,需要之后对各个设计模式的学习理解和消化。

  • 为什么要使用设计模式呢?
  1. 可以提高程序员的思维能力、编程能力和设计能力。
  2. 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  3. 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。

2、单例模式

我们上面简单的介绍了一下设计模式是什么,为什么要学习设计模式,之后我们将从各个设计模式的使用来进行讲解。记住,设计模式是一种思想,我们一定要尽可能地理解它。当然,如果暂时理解不了的话,也不要灰心,慢慢来消化即可。加油吧,骚年!!!

在这里插入图片描述

2.1、什么是单例模式?

单例模式(英文名:Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建(所以说如果该类是单例模式的话,那么你使用到的它的每一个对象都是相同的。)。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

  • 单例模式的主要有以下角色:
  1. 单例类只能创建一个实例的类
  2. 访问类:使用单例类

2.2、单例模式实现方式

单例设计模式分类两种(主要区别在于是否在类加载的时候进行相关单实例对象的创建):

饿汉式:类加载就会导致该单实例对象被创建

懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建

  • 饿汉式 - 方式1
/**
 * @author :小肖
 * 饿汉式方式1:静态成员变量
 * @date :Created in 2022/5/5 14:58
 */
public class Singleton {

    // 1. 私有构造
    private Singleton() {
    }

    // 2. 静态成员变量
    private static Singleton instance = new Singleton();

    // 3. 公有的获取方法
    public static Singleton getInstance() {
        return instance;
    }
}

测试方法

/**
 * @author :小肖
 * @date :Created in 2022/5/5 15:00
 */
public class Test {
    public static void main(String[] args) {
        // 获取第一个实例
        Singleton instance = Singleton.getInstance();

        // 获取第二个实例
        Singleton instance1 = Singleton.getInstance();

        // 比较两个实例是否相等
        System.out.println(instance == instance1);
    }
}

输出结果

true
  • 饿汉式 - 方式2
/**
 * @author :小肖
 * 饿汉式方式2:静态代码块
 * @date :Created in 2022/5/5 15:05
 */
public class Singleton {

    // 1. 私有构造
    private Singleton() {
    }

    // 2. 私有静态变量
    private static Singleton instance;

    // 3. 静态代码块进行创建对象
    static {
        instance = new Singleton();
    }

    // 4. 公有的获取方式
    public static Singleton getInstance() {
        return instance;
    }
}

总的说明:我们观察上述的代码可以发现,我们是将对应的类的构造方法私有,进而防止外部进行创建该类对象,同时在类内部直接创建好对象,从而使得对象是单例的,但可能创建的方式不同。但不管是使用静态代码块的方式创建对象,还是直接创建对象,它们都是在类加载的时候就进行了相关对象的创建,如果我们之后没有对其进行使用,或者说之后的代码中并未使用到该对象,那么这样加载的对象就是浪费了相关内存的。这也是饿汉式的缺点所在,那么也就引申出了 懒汉式实现方式

  • 懒汉式 - 线程不安全
/**
 * @author :小肖
 * 懒汉式实现
 * @date :Created in 2022/5/5 15:23
 */
public class Singleton {

    // 1. 私有构造方法
    private Singleton() {
    }

    // 2. 静态成员变量
    private static Singleton instance; // null

    // 3. 公有获取方法
    public static Singleton getInstance() {
        if (instance == null) {
            return new Singleton();
        }
        return instance;
    }
}

为什么线程不安全呢?

当线程1读取到当前 instancenull 的时候,那么此时如果就将 cpu 让出给线程2使用的话,那么此时线程2 读取到的当前 instance 也为 null,那么就会导致两个线程创建了多个实例对象,所以在多线程环境下是不安全的。

  • 懒汉式 - 线程安全
/**
 * @author :小肖
 * 懒汉式实现
 * @date :Created in 2022/5/5 15:23
 */
public class Singleton {

    // 1. 私有构造方法
    private Singleton() {
    }

    // 2. 静态成员变量
    private static Singleton instance; // null

    // 3. 公有获取方法
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            return new Singleton();
        }
        return instance;
    }
}

虽然这种方式能够解决多线程线程安全问题,但是你要知道 synchronized 是重量级锁,虽然 JVM 底层对它进行了相关的优化,但是还是会带来很大的性能消耗。因为这个方法大多数情况下是读操作,所以只有当需要创建对应的实例对象的时候才需要进行对应的加锁的必要,那么我们可以使用 双重检查锁 + volatile 实现一种更好的单例模式。

  • 懒汉式 - 线程安全(双重检查锁 + volatile)
/**
 * @author :小肖
 * 懒汉式 双重检查锁 + volatile
 * @date :Created in 2022/5/5 15:48
 */
public class Singleton {
    
    // 1. 私有构造
    private Singleton() {}
    
    // 2. 静态成员变量
    private static volatile Singleton instance;
    
    // 3. 公有获取方式
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    return instance;
                }
            }
        }
        return instance;
    }
}

这里需要注意,我们为什么要在对应的变量上加 volatile 关键字呢?

因为在多线程的情况下,它还是会造成我们对应的单例对象是空指针的情况,该情况主要是由于虚拟机优化和指令重排造成的。所以说我们可以通过加上 volatile 使得消除这种指令重排。

当然这里还有两种实现单例模式的方式:静态内部类的实现方式、枚举的实现方式。这里我就不一一介绍了。

2.3、单例模式存在的问题

其实单例模式维护的核心就是保证对应的实例对象是唯一的,那么就肯定会有人想方设法的去破环这种唯一性。这就是单例模式所存在的问题了。

破坏方式

  1. 通过序列化和反序列化的方式可以对单例模式进行破坏。
  2. 通过反射机制可以对单例模式进行破坏。

解决方式

  1. Singleton 类中添加 readResolve() 方法,在反序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新 new 出来的对象。
  2. 当通过反射方式调用构造方法进行创建时,如果对应的对象为null的话,直接抛异常。

2.4、JDK源码中使用到的单例模式

Runtime 类就是使用的单例设计模式。

   public class Runtime {
       private static Runtime currentRuntime = new Runtime();
   
       /**
        * Returns the runtime object associated with the current Java application.
        * Most of the methods of class <code>Runtime</code> are instance
        * methods and must be invoked with respect to the current runtime object.
        *
        * @return  the <code>Runtime</code> object associated with the current
        *          Java application.
        */
       public static Runtime getRuntime() {
           return currentRuntime;
       }
   
       /** Don't let anyone else instantiate this class */
       private Runtime() {}
       ...
   }

从上面源代码中可以看出 Runtime 类使用的是饿汉式(静态属性)方式来实现单例模式的。

编写不易,如果你感觉对你有帮助的话,请你三连支持,后面的文章会一点点更新。

在这里插入图片描述

相关文章
|
24天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
27 2
|
5天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
13天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
13 1
|
29天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
25天前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy&lt;T&gt;` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
29 1
|
30天前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。
|
1月前
|
设计模式 存储 测试技术
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发领域,设计模式是解决常见问题的最佳实践。本文将深入探讨单例模式,一种确保类只有一个实例的设计模式,并提供实际应用示例。我们将从单例模式的基本概念讲起,通过实际案例展示如何在PHP中实现单例模式,以及它在不同场景下的应用和优势。最后,我们会探讨单例模式的优缺点,帮助开发者在实际项目中做出明智的选择。
|
1月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP开发领域,设计模式是解决常见问题的高效方案集合。它们不是具体的代码,而是一种编码和设计经验的总结。单例模式作为设计模式中的一种,确保了一个类仅有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的基本概念、实现方式及其在PHP中的应用。
单例模式在PHP中的应用广泛,尤其在处理数据库连接、日志记录等场景时,能显著提高资源利用率和执行效率。本文从单例模式的定义出发,详细解释了其在PHP中的不同实现方法,并探讨了使用单例模式的优势与注意事项。通过对示例代码的分析,读者将能够理解如何在PHP项目中有效应用单例模式。
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入探讨与实践
在PHP开发领域,设计模式是提升代码可读性、可维护性和扩展性的重要工具。本文聚焦于单例模式——一种确保类只有一个实例,并提供全局访问点的设计模式。我们将从定义、实现方式、应用场景以及在PHP框架中的运用等方面进行详细探讨,旨在帮助PHP开发者更好地理解和运用单例模式。
|
19天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
22 0
下一篇
无影云桌面