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

java 设计模式之单例模式

简介

单例模式:一个类有且仅有一个实例,该类负责创建自己的对象,同时确保只有一个对象被创建。

特点:类构造器私有、持有自己实例、对外提供获取实例的静态方法。

单例模式的实现方式

饿汉式

类被加载时,就会实例化一个对象并交给自己的引用,供系统使用;而且,由于这个类在整个生命周期中只会被加载一次,因此只会创建一个实例,即能够充分保证单例。

案例:

public class Singleton {private static Singleton instance = new Singleton();private Singleton() { }public static Singleton getInstance() {return instance;}
}

饿汉式比较耗费资源,因为它创建单例的时间过早,它是在类被加载的时候创建单例的

懒汉式加双重检查加锁

饿汉式的优化,只有在获取类的实例时才会创建实例。

案例:

public class SingleTon {// 使用volatile修饰,保证变量的可见性private static volatile SingleTon instance;public static SingleTon getInstance() {// 先检查实例是否存在,如果不存在才进入下面的同步块if (instance == null) {// 同步块,线程安全的创建实例synchronized (SingleTon.class) {// 再次检查实例是否存在,如果不存在才真的创建实例if (instance == null) {instance = new SingleTon();}}}return instance;}
}

饿汉式中的注意事项:

1、为什么类持有的自己的私有实例要用volatile修饰:为了保证指定变量的有序性和可见性。new一个对象的代码 SingleTon instance = new SingleTon(); 可以分解为3行伪代码:

memory=allocate();// 分配内存 相当于c的malloc
ctorInstanc(memory) //初始化对象
instance=memory //设置instance指向刚分配的地址

上面的代码在编译器运行时,可能出现重排序,从 1-2-3 变为 1-3-2,在多线程环境下就会出现问题,使用 volatile 关键字会禁止这种重排序。

2、为什么要双重锁:如果只有一个锁,很有可能两个线程都通过了 if(instance == null) 的判断,所以在进入同步代码块之后还需要再判断一次

用静态内部类来实现单例模式

案例:

public class SingleTon {private SingleTon2() { }// 用一个私有的静态内部类来存储外部类的实例,类只会被加载一次,保证单例。// 内部类只有在被调用时才会被加载,保证了延迟加载private static class SingleTonHolder {private static SingleTon2 instance = new SingleTon2();}public static SingleTon2 getInstance() {return SingleTonHolder.instance;}
}

破坏单例模式

破坏单例模式:序列化和反射可以破坏单例模式。

  • 解决序列化破坏单例的问题:在类中添加readResolve方法,返回类中的实例,可以解决通过序列化破坏单例模式的问题;
  • 解决反射破坏单例的问题:在构造方法中抛异常,可以解决通过反射破坏单例模式的问题

单例模式的使用案例

饿汉式单例模式的使用:jdk中的Runtime类,每个java程序中都只有一个Runtime实例,它代表java程序的运行环境

public class Runtime {// 类被加载时,就会实例化一个对象并交给自己的引用private static Runtime currentRuntime = new Runtime();// 返回单例对象的方法public static Runtime getRuntime() {return currentRuntime;}// 私有化的构造方法/** Don't let anyone else instantiate this class */private Runtime() {}
}
http://www.xdnf.cn/news/32.html

相关文章:

  • 利用互斥锁或者利用逻辑过期解决缓存击穿问题
  • 【Linux我做主】探秘gcc/g++和动静态库
  • 22、字节与字符的概念以及二者有什么区别?
  • 【含文档+PPT+源码】基于微信小程序的非遗文化黄梅戏宣传平台的设计与实现
  • Oracle补丁安装工具opatch更新报错处理
  • pytorch学习02
  • ESP32之OTA固件升级流程,基于VSCode环境下的ESP-IDF开发,基于阿里云物联网平台MQTT-TLS连接通信(附源码)
  • HttpSessionBindingListener 的用法笔记250417
  • vscode与vim+cscope+tags热键冲突
  • Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑
  • 大模型时代下全场景数据消费平台的智能BI—Quick BI深度解析
  • Hyperf (Swoole)的多进程 + 单线程协程、Gin (Go)Go的单进程 + 多 goroutine 解说
  • 【android telecom 框架分析 01】【基本介绍 2】【BluetoothPhoneService为何没有源码实现】
  • Oracle测试题目及笔记(多选)
  • CentOS 7 安装教程
  • Python自学第2天:条件语句,循环语句
  • 阿尔特拉 EP1C12F324I7N AlteraFPGA Cyclone
  • Go语言从零构建SQL数据库(8):执行计划的奥秘
  • 名胜古迹传承与保护系统(springboot+ssm+vue+mysql)含运行文档
  • FortiAI 重塑Fortinet Security Fabric全面智能化进阶
  • Android studio前沿开发--利用socket服务器连接AI实现前后端交互(全站首发思路)
  • nginx中的代理缓存
  • XCZU7EG‑L1FFVC1156I 赛灵思XilinxFPGA ZynqUltraScale+ MPSoC EG
  • Vscode 插件开发
  • 【NLP 63、大模型应用 —— Agent】
  • 【Pytorch之一】--torch.stack()方法详解
  • 学习笔记十五——rust柯里化,看不懂 `fn add(x) -> impl Fn(y)` 的同学点进来!
  • Mac配置Java的环境变量