什么是单例模式?单例模式的作用?单例模式的使用场景等...

设计模式(一)单例模式详解

一、单例模式

什么是单例模式?

单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。在Java中,单例模式通过以下几种方式实现:

  1. 将构造方法私有化,防止外部直接创建实例。

  2. 定义一个静态变量来保存唯一的实例。

  3. 提供一个公共的静态方法来返回这个实例。

单例模式的作用?
  1. 资源节约:确保系统中某个类只有一个实例,减少不必要的内存开销。

  2. 全局访问:提供一个全局访问点,方便在整个应用中访问同一个实例。

  3. 控制共享资源访问:确保对共享资源的访问是安全的且一致的。

为什么使用单例模式?
  • 简化配置管理:对于需要频繁实例化然后销毁的对象,使用单例模式可以简化配置管理。

  • 降低耦合度:通过单例模式,系统中的所有对象都可以通过一个统一的方式访问某个实例,从而降低类之间的耦合度。

  • 避免多线程问题:多线程环境中,单例模式可以保证对象的唯一性,避免多线程同时操作同一个对象带来的问题。

单例模式的使用场景
  1. 日志文件管理:系统中通常只需要一个日志文件管理器来记录日志信息。

  2. 数据库连接池:为了提高性能,数据库连接池通常设计成单例模式,避免每次连接数据库时都要重新创建连接。

  3. 任务调度器:在一个系统中往往只需要一个任务调度器来管理任务的执行。

  4. 配置管理:应用程序的配置信息通常只需要加载一次,因为此配置管理类适合采用单例模式实现。

单例模式的分类
1、懒汉式1(线程不安全的)多线程环境下会出错。

懒加载:只有在第一次调用getInstance()方法时才会创建实例

java 复制代码
package com.briup.singletonMyself;

/**
 * 懒汉式单例1(线程不安全的)
 * @author 35329
 */
public class LazySingleton1 {
    // 声明一个保存本类实例引用的静态变量
    private static LazySingleton1 instance;

    // 将构造方法私有化、防止其他类创建该类对象
    private LazySingleton1(){

    }

    // 提供一可以获取唯一实例的静态方法
    public static LazySingleton1 getInstance(){
        if (instance == null){
            instance = new LazySingleton1();
        }
        return instance;
    }
}
2、懒汉式2(线程安全)使用synchronized关键字保证线程安全,但每次调用getInstance()方法都会加锁,性能较低。
java 复制代码
package com.briup.singletonMyself;

/**
 * @author 35329
 *
 * 懒汉式单例2(线程安全的)
 */
public class LazySingleton2 {
    // instance: 实例
    private static LazySingleton2 instance;
    // 私有的构造器
    private LazySingleton2(){

    }

    // 专门创建一个静态性质的对象,充当同步锁
    private final static Object lock = new Object();

    // 提供一个方法,用于获取该实例
    public static LazySingleton2 getInstance(){
        synchronized (lock){
            if (instance == null){
                instance = new LazySingleton2();
            }
        }
        return instance;
    }
}
3、懒汉式3(使用synchronized和volatile修饰符确保多线程环境下的安全性,同时避免了每次调用getInstance()方法时都进行同步的性能开销)
java 复制代码
package com.briup.singletonMyself;

/**
 * @author 35329
 * 懒汉式单例3:
 * 1、对对象的创建和判断是否为空的操作 以原子性执行
 * 2、将类中的实例instance使用volatile修饰符修饰
 */
public class LazySingleton3 {

    // instance : 静态变量,用来保存单例对象的唯一实例。
    // volatile修饰符:确保多线程环境下instance的可见性和有序性,
    // 防止指令重排导致的问题
    private volatile static LazySingleton3 instance;
    // 将构造方法私有化
    private LazySingleton3(){

    }
    // 使用静态对象作为同步锁,确保线程安全
    private final static Object lock = new Object();

    // 专门提供一个方法,用于获取该实例
    public static LazySingleton3 getInstance(){
        // synchronized(lock)确保在多线程环境下getInstance()方法内的代码块是同步执行的。
        synchronized (lock){
            // 只有确保在instance为null时才会创建新的实例
            if (instance == null){
                instance = new LazySingleton3();
            }
        }
        return instance;
    }
}
4、懒汉式+线程同步+可见性+DCL(双重锁验证机制)
java 复制代码
package com.briup.singletonMyself;

/**
 * @author 35329
 * 单例模式:懒汉式+线程同步+可见性+DCL
 * DCL:Double Check Lock,双重锁验证机制
 */
public class DCLSingleton {
    // instance 实例
    private volatile static DCLSingleton instance;
    // 私有构造器
    private DCLSingleton(){

    }
    // 同步锁 确保线程安全
    private static final Object lock = new Object();

    // 提供一个方法,用于获取该实例
    public static DCLSingleton getInstance(){
        if (instance == null){
            // synchronized (DCLSingleton.class) 这两句相同 详细解析看下方注释
            synchronized (lock){
                if (instance == null){
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
    /*
     * synchronized (DCLSingleton.class) 是DCLSingleton类的对象引用
     * 类对象锁是针对类对象的锁,可以确保在类加载时只有一个线程能够进入同步块
     * 
     * synchronized(lock) 是一个普通的对象引用,对象锁是针对特定对象的锁,
     * 可以确保在多线程的环境下只有一个线程能够进入同步块。
     * 由于lock是静态对象,因此所有对DCLSingleton类的实例化操作都会受到这个锁的影响。
     * 这种方式可以确保在多线程环境下,只有一个线程能够进入同步块并创建实例。
     * 
     * 这两种方式都能保证线程安全,但synchronized(lock)更常用,因为它不会影响
     * 类的其他操作。而synchronized(XXXXX.class)虽然也能保证线程安全,但可能会影响类的其他操作。
     * 具体选择那种方式取决于实际需求和性能考虑。
     */
}
5、饿汉式
java 复制代码
package com.briup.singletonMyself;

/**
 * 饿汉式单例:不使用显示初始化,而是使用static{}对实例进行创建
 */
public class HungrySingleton {

    // 创建一个Hungry类的唯一实例
    private final static HungrySingleton INSTANCE;
    
    static {
        INSTANCE = new HungrySingleton();
    }

    // 私有构造函数,防止外部实例化
    private HungrySingleton(){

    }
    
    // 提供一个公共的静态方法,用于返回唯一的实例
    public static HungrySingleton getInstance(){
        return INSTANCE;
    }
}
6、静态内部类
java 复制代码
package com.briup.singletonMyself;

/**
 * @author 35329
 * 单例模式:借助静态内部类实现
 */
public class StaticInnerSingleton {
    // 将构造器私有化,防止外界创建该类对象
    private StaticInnerSingleton(){

    }

    /**
     * InstanceHolder是一个静态内部类,它持有StaticInnerSingleton的唯一实例
     *
     * INSTANCE:是一个静态最终变量,用于保存StaticInnerSingleton的唯一实例
     *
     * 静态内部类InstanceHolder只会在首次访问getInstance()方法时被加载,
     * 此时INSTANCE会被初始化。由于类加载是线程安全的,因此这种方法保证了线程的安全
     */
    private static class InstanceHolder{ // 外部类实例的持有者
        // 将外部类的唯一实例声明在这里
        private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();

    }
    
    // 提供了一个静态方法用于获取唯一的实例
    // 懒加载:只有在首次调用getInstance()方法时才会创建实例,之后每次调用都会返回已创建的实例
    public static StaticInnerSingleton getInstance(){
        return InstanceHolder.INSTANCE;
    }

}
7、枚举
java 复制代码
package com.briup.singletonMyself;

/**
 * @author 35329
 * 
 * 单例模式:枚举实现
 * 过早的将对象创建出来加载到内存,但是线程是安全的,简洁,推荐使用
 */
public enum EnumSingleton {
    INSTANCE;  // 唯一的实例
    
    // 定义一个静态方法 用来返回该实例的方法
    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

++后续设计模式等待更新中...++

相关推荐
禁默37 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood44 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
zfoo-framework1 小时前
【jenkins插件】
java
风_流沙1 小时前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
ProtonBase2 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v2 小时前
leetCode43.字符串相乘
java·数据结构·算法