深入浅出 - 单例模式

简介: 深入浅出 - 单例模式

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

1687787675204.jpg

1、什么是单例模式

单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在单例模式中,该类的构造函数必须是私有的,以防止其他代码创建该类的实例。而且,该类必须提供一个静态方法来获取其唯一实例。

单例模式常用于需要共享资源的情况,例如数据库连接池、线程池、配置文件等。由于只有一个实例存在,因此可以避免资源的浪费和冲突。

单例模式有多种实现方式,例如饿汉式、懒汉式、双重检查锁等。其中,饿汉式在类加载时就创建了唯一实例,因此线程安全,但可能会浪费资源。懒汉式在第一次使用时才创建唯一实例,避免了资源浪费,但需要考虑线程安全问题。双重检查锁则结合了两种方式的优点,既能保证线程安全,又能避免资源浪费。

2、单例模式有多少种写法

单例模式有以下几种常见的实现方式:

  1. 饿汉式单例模式:在类加载时就创建唯一实例,线程安全,但可能会浪费资源。

  2. 懒汉式单例模式:在第一次使用时才创建唯一实例,避免了资源浪费,但需要考虑线程安全问题。

  3. 双重检查锁单例模式:结合了饿汉式和懒汉式的优点,既能保证线程安全,又能避免资源浪费。

  4. 静态内部类单例模式:利用静态内部类的特性,在类加载时不会创建唯一实例,只有在第一次使用时才创建,既能保证线程安全,又能避免资源浪费。

  5. 枚举单例模式:利用枚举类型的特性,保证只有一个实例存在,线程安全,且代码简洁。

    以上是常见的几种单例模式的实现方式,每种实现方式都有其优缺点,需要根据具体情况选择适合的实现方式。

3、饿汉式单例模式

饿汉式单例模式是一种单例模式的实现方式。在该实现方式中,单例对象在类加载时就被创建了,因此也被称为“饿汉式”(即“饥不择食”的意思)。具体来说,饿汉式单例模式的实现方式是将单例对象声明为静态变量,并在类加载时就进行初始化,这样在后续使用时就可以直接获取该静态变量的值,无需再创建新的实例。由于该实现方式在类加载时就创建了单例对象,因此不存在线程安全问题。

饿汉式的代码如下:

package com.pany.camp.design.principle;

/**
 *
 * @description: 饿汉式单例模式
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-26 21:39
 */
public class Singleton {
   
   

    // 在类加载时就创建唯一实例
    private static Singleton instance = new Singleton();

    // 将构造函数设为私有,防止其他代码创建实例
    private Singleton() {
   
   
    }

    // 提供静态方法获取唯一实例
    public static Singleton getInstance() {
   
   
        return instance;
    }
}

4、 懒汉式单例模式

懒汉式单例模式是一种单例模式的实现方式。在该实现方式中,单例对象在第一次使用时才被创建,因此也被称为“懒汉式”。具体来说,懒汉式单例模式的实现方式是将单例对象的初始化延迟到第一次使用时,而不是在类加载时就进行初始化。在第一次使用时,如果该单例对象还没有被创建,则创建一个新的实例并返回,否则直接返回已经存在的实例。由于该实现方式在第一次使用时才创建单例对象,因此存在线程安全问题,需要进行相应的线程安全处理,例如使用 synchronized 关键字或者双重检查锁等方式。

代码如下:

package com.pany.camp.design.principle;

/**
 *
 * @description:  懒汉式单例模式
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-26 21:43
 */
public class Singleton1 {
   
   

    // 声明静态的、私有的单例变量
    private static Singleton1 instance;

    // 将构造函数设为私有,防止其他代码创建实例
    private Singleton1() {
   
   
    }

    // 提供静态方法获取唯一实例
    public static synchronized Singleton1 getInstance() {
   
   
        if (instance == null) {
   
   
            instance = new Singleton1();
        }
        return instance;
    }
}

懒汉式单例模式的主要问题是线程安全。在多线程环境下,如果多个线程同时调用 getInstance() 方法,可能会导致创建多个实例,从而违反了单例模式的原则。具体来说,如果一个线程在检查 instancenull 时被挂起了,而另一个线程在此时也调用了 getInstance() 方法并创建了实例,那么当第一个线程恢复执行时,它也会创建一个新的实例,从而导致多个实例的产生。为了解决这个问题,可以使用 synchronized 关键字或者双重检查锁等方式来保证线程安全,但这些方式会带来一定的性能损失。

5、双重检查锁单例模式

双重检查锁单例模式是一种单例模式的实现方式,它通过双重检查来保证线程安全和性能。具体来说,该实现方式在第一次使用时才创建单例对象,并使用双重检查来确保在多线程环境下只创建一个实例。

代码如下:

package com.pany.camp.design.principle;

/**
 *
 * @description:  双重检查锁单例模式
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-26 21:45
 */
public class Singleton3 {
   
   

    // 声明静态的、私有的单例变量
    private static volatile Singleton3 instance;

    // 将构造函数设为私有,防止其他代码创建实例
    private Singleton3() {
   
   
    }

    // 提供静态方法获取唯一实例
    public static Singleton3 getInstance() {
   
   
        if (instance == null) {
   
   
            synchronized (Singleton3.class) {
   
   
                if (instance == null) {
   
   
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

Singleton3 类的构造函数被设为私有,防止其他代码创建该类的实例。 instance 静态变量被声明为私有的、静态的、volatile 的,它的初始值为 null 。 getInstance() 方法提供了获取唯一实例的静态方法,该方法使用了双重检查锁来保证线程安全和性能。在方法内部,首先检查 instance 是否为 null ,如果是,则进入同步块。在同步块内部,再次检查 instance 是否为 null ,如果是,则创建一个新的 Singleton3 实例并将其赋值给 instance 。由于使用了双重检查锁,因此可以避免在多线程环境下创建多个实例的问题,并且也可以减少同步的开销。需要注意的是, instance 变量必须声明为 volatile,以确保在多线程环境下的可见性。

6、静态内部类单例模式

静态内部类单例模式是一种单例模式的实现方式,它使用静态内部类来实现单例对象的延迟初始化,从而避免了线程安全问题和性能问题。具体来说,该实现方式在静态内部类中声明单例对象,当外部类第一次使用单例对象时,才会加载静态内部类并创建单例对象。

代码如下:

package com.pany.camp.design.principle;

/**
 *
 * @description: 静态内部类单例模式
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-26 21:47
 */
public class Singleton4 {
   
   

    // 将构造函数设为私有,防止其他代码创建实例
    private Singleton4() {
   
   
    }

    // 静态内部类,用于延迟初始化单例对象
    private static class SingletonHolder {
   
   
        private static final Singleton4 INSTANCE = new Singleton4();
    }

    // 提供静态方法获取唯一实例
    public static Singleton4 getInstance() {
   
   
        return SingletonHolder.INSTANCE;
    }
}

Singleton4 类的构造函数被设为私有,防止其他代码创建该类的实例。 SingletonHolder 静态内部类用于延迟初始化单例对象,其中 INSTANCE 静态变量被声明为 final ,并在静态初始化块中创建了一个新的 Singleton 实例。 getInstance() 方法提供了获取唯一实例的静态方法,该方法直接返回 SingletonHolder 中的 INSTANCE 变量。由于静态内部类只会在第一次使用时加载,因此可以保证单例对象的延迟初始化,并且由于静态内部类的加载是线程安全的,因此可以避免线程安全问题。同时,由于单例对象的创建是在静态初始化块中进行的,因此也可以避免性能问题。

7、枚举单例模式

枚举单例模式是一种单例模式的实现方式,它使用枚举类型来实现单例对象的创建。在 Java 中,枚举类型是线程安全的,且只会被初始化一次,因此可以保证枚举单例模式的线程安全性和单例性。

代码如下:

package com.pany.camp.design.principle;

/**
 *
 * @description: 枚举单例模式
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-26 21:49
 */
public enum Singleton5 {
   
   

    INSTANCE;
    // 添加其他方法和属性
}

Singleton5 枚举类型只有一个枚举常量 INSTANCE ,它是一个单例对象。由于枚举类型只会被初始化一次,因此可以保证 INSTANCE 的单例性。同时,由于枚举类型是线程安全的,因此可以保证 INSTANCE 的线程安全性。需要注意的是,由于枚举类型不能被继承,因此枚举单例模式不能被子类化,但是可以添加其他方法和属性。

8、哪些写法是完美的单例写法

静态内部类单例模式 、枚举单例模式是常用的完美的单例写法。实际项目中我用的最多的就是

1686494501743.jpg

💕💕 本文由激流丶创作,原创不易,感谢支持!
💕💕喜欢的话记得点赞收藏啊!

目录
相关文章
|
4月前
|
设计模式 安全 Java
【设计模式系列笔记】单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点,以便全局范围内访问这个实例。单例模式的目标是限制一个类的实例化,确保在整个应用程序中只有一个实例存在,并提供对这个唯一实例的全局访问点。这对于控制对资源的访问、限制特定类的实例数量等场景非常有用。
143 5
|
10月前
|
设计模式 安全 Java
设计模式系列教程(04) - 单例模式
设计模式系列教程(04) - 单例模式
43 0
设计模式系列教程(04) - 单例模式
|
19天前
|
设计模式 安全 Java
Java编程中的单例模式实现与应用
【8月更文挑战第31天】在Java的世界里,单例模式是构建高效且资源友好应用的基石之一。本文将深入浅出地介绍如何通过单例模式确保类只有一个实例,并提供一个全局访问点。我们将探索多种实现方法,包括懒汉式、饿汉式和双重校验锁,同时也会讨论单例模式在多线程环境下的表现。无论你是Java新手还是资深开发者,这篇文章都将为你打开一扇理解并有效应用单例模式的大门。
|
设计模式 存储 安全
Java设计模式:深入探讨饿汉式单例模式
当谈到Java设计模式时,"单例模式"是一个必不可少的主题。在这篇文章中,我们将深入探讨单例模式的一种常见实现方式——"饿汉式"。我们将了解什么是饿汉式单例模式,为什么选择它,以及如何在Java中实现。
255 0
|
4月前
|
设计模式 Java
深入浅出工厂模式
深入浅出工厂模式
32 0
|
设计模式 关系型数据库 MySQL
你知道独生子女用编程怎么表示吗?单例模式了解一下
你知道独生子女用编程怎么表示吗?单例模式了解一下
73 1
你知道独生子女用编程怎么表示吗?单例模式了解一下
|
设计模式 SQL 安全
【设计模式学习笔记】单例模式详解(懒汉式遇上多线程问题解析基于C++实现)
【设计模式学习笔记】单例模式详解(懒汉式遇上多线程问题解析基于C++实现)
326 0
【设计模式学习笔记】单例模式详解(懒汉式遇上多线程问题解析基于C++实现)
|
设计模式 Java
面试基础篇——单例模式(二)
面试基础篇——单例模式
80 0
|
设计模式 安全 Java
面试基础篇——单例模式(一)
面试基础篇——单例模式
95 0
|
SQL 设计模式 安全
Java设计模式 | 单例模式解析与实战
Java设计模式 | 单例模式解析与实战