当前位置: 首页 > news >正文

设计模式简述(二)单例模式

单例模式

  • 描述
  • 基本使用
    • 防破坏单例
    • 饿汉式
    • 懒汉式
    • 有上限多例

描述

一个类全局只有一个实例,自行实例化并提供给使用。
构造函数私有化是前提

基本使用

防破坏单例

  • 防反射:在构造函数中判断类中实例是否已初始化
private InnerClassSingleton (){
    if(InnerClassSingletonHolder.instance != null){
        throw new RuntimeException("单例模式 不允许 多例存在");
    }
}
  • 防克隆:单例类不要实现Cloneable接口或者强制覆盖clone方法
    如果采用的是强制覆盖clone方法,可以返回单例对象或者 直接报错
  • 防序列化:对象反序列化会调用对象的readResolve方法,可以在类中声明这个方法,并返回单例对象
    Object readResolve() throws ObjectStreamException{
        return InnerClassSingletonHolder.instance;
    }

饿汉式

  • 静态成员初始化
public class HungrySingleton {

    private static HungrySingleton instange = new HungrySingleton();

    private HungrySingleton() {
        if (instange != null) {
            throw new RuntimeException("单例模式不允许 多例存在");
        }
    }

    public static HungrySingleton getInstance() {
        return instange;
    }
}
  • 静态代码块初始化
public class HungrySingleton {

    private static HungrySingleton instange;
    static {
    	instange = new HungrySingleton();
    }
    private HungrySingleton() {
        if (instange != null) {
            throw new RuntimeException("单例模式不允许 多例存在");
        }
    }

    public static HungrySingleton getInstance() {
        return instange;
    }
}
  • 枚举(直接用吧JVM层面保证单例)
/**
 * @author sdaf
 * <p>
 * 枚举:本质也是一个类,底层是一个实现 Eunm 的一个类,编译器会默认添加一些属性及方法
 * 枚举站在单例实现角度上看 就是一个饿汉模式实现
 */
public enum EnumSingleton {
    INSTANGE;
    public void test(){
    // code
    }
}

懒汉式

  • synchronized + double check
public class LazySingleton {

    private static volatile LazySingleton lazySingleton;

    private LazySingleton() {
        if(lazySingleton!=null){
            throw new RuntimeException("单例模式不允许 多例存在");
        }
    }

    public static LazySingleton getInstance() {
        if (lazySingleton == null) {
            // 线程A 线程B 均进入非空判断逻辑
            // 线程A 先行添加锁,然后创建实例对象,并返回
            // 此时线程B已经 进入非空的逻辑,然后依然会去加锁,然后创建对象,此时就违背了单例对象定义
            // 所以需要在加锁的内部再次进行非空判断,保证对象单例
            synchronized (LazySingleton.class) {
                if (lazySingleton == null) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lazySingleton = new LazySingleton();
                    // new 一个对象步骤进一步解析
                    // 1、在堆内存开辟一块空间
                    // 2、初始化对象(创建对象)
                    // 3、将开辟的内存空间地址赋值给变量
                    // 【但是】由于编译器和CPU的指令重排可能导致 2 和 3 执行顺序发生改变
                    // 为 1 3 2
                    // 此时如果第二个线程 在 第一个线程执行到 3 与 2之间时 进来
                    // instance 是有值的,因为 instance 拿到的只是 内存地址而已,并不知道这个地址上是否实在的对象
                    // 只有当这个对象完成初始化(创建)后这个地址上才有具体的值
                    // 此时第二个线程拿到地址就会直接返回这个引用,
                    // 但是此时这个对象是个 null , 可能会引起 NullPointerException
                    // 为了防止 整个 new 操作被执行重排 需要使用关键字 volatile 来修饰变量
                }
            }
        }
        return lazySingleton;
    }
  • 静态内部类
/**
 * @author sdaf
 * @Description 基于静态内部类的单例模式,也是一种懒加载
 * 也是借助于JVM类加载机制实现的线程安全
 * 类加载顺序:
 * 1.加载类的Class文件到内存中
 * 2.连接JVM,验证Class合法性,静态成员赋默认值,解析处理后的数据
 * 3.给静态成员赋值
 * 静态内部类只有在使用这个类的时候才会去加载这个类
 */
public class InnerClassSingleton implements Serializable{

    private static final long serialVersionUID = -790330830636259886L;

    private static class InnerClassSingletonHolder{
        private static InnerClassSingleton instance= new InnerClassSingleton();
    }
    private InnerClassSingleton (){
        if(InnerClassSingletonHolder.instance != null){
            throw new RuntimeException("单例模式 不允许 多例存在");
        }
    }

    public static InnerClassSingleton getInstance(){
        return InnerClassSingletonHolder.instance;
    }
//
    Object readResolve() throws ObjectStreamException{
        return InnerClassSingletonHolder.instance;
    }
}

有上限多例

单例模式可以扩展为有上限多例

public class Multiton {
    private Multiton() {}
    private static final int MAX_INSTANCES = 3;
    private static final List<Multiton> instances = new ArrayList<>();

    // 饿汉式初始化
    static {
        for (int i = 0; i < MAX_INSTANCES; i++) {
            instances.add(new Multiton());
        }
    }
    // 懒汉式初始化
    public static Multiton getInstanceLazy(int index) {
        if (instances.get(index) == null) {
            synchronized (Multiton.class) {
                if (instances.get(index) == null) {
                    instances.set(index, new Multiton());
                }
            }
        }
        return instances.get(index);
    }


    // 随机获取
    public static Multiton getRandomInstance() {
        Random random = new Random();
        return instances.get(random.nextInt(MAX_INSTANCES));
    }

    // 指定获取
    public static Multiton getInstance(int index) {
        if (index < 0 || index >= MAX_INSTANCES) {
            throw new IllegalArgumentException("索引超出范围");
        }
        return instances.get(index);
    }
    
    // 业务方法
    public void test() {
        
    }
}
http://www.dtcms.com/a/112826.html

相关文章:

  • Turnitin论文查重检测注意事项有哪些?
  • Centos7上安装docker - yum在线的方式
  • Kafka 如何解决消息堆积问题?
  • 软件工程面试题(二十九)
  • Kafka Consumer Group
  • Python-文件操作
  • Photoshop 2025 Mac中文Ps图像编辑
  • Python3 学习笔记
  • 《AI大模型趣味实战》智能财务助手系统架构设计
  • PE结构(十五)系统调用与函数地址动态寻找
  • 技术驱动革新,强力巨彩LED软模组助力创意显示
  • 搭建K8S-1.23
  • P1577 切绳子(二分)
  • tomcat与spring-web
  • 智能工厂的数字孪生与信息物理系统架构研究
  • 【MiniMind】不能全局用 `pip install --upgrade pip`
  • 在 Langflow 中构建灵活的自定义组件:从基础到高级实践
  • 双向链表增删改查的模拟实现
  • 初步了解 JVM
  • 贪心算法之Huffman编码
  • a标签download下载图片
  • 【模型量化】GPTQ 与 AutoGPTQ
  • Kafka 如何保证消息可靠性?
  • K8s的BackUP备份
  • 理解OSPF 特殊区域NSSA和各类LSA特点
  • [c语言日寄]预处理命令详解
  • 树欲静而风不停
  • 无人机飞行术语科普!
  • 第九课:LoRA模型的原理及应用
  • Vue中权限控制的方案