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

设计模式 -- 单例设计模式

1.1 单例

创建一个单例对象 SingleModel , SingleModel 类有它的私有构造函数和本身的一个静态实例。
SingleModel 类提供了一个静态方法,供外界获取它的静态实例。 DesignTest 我们的演示类使用
SingleModel 类来获取 SingleModel 对象。
创建 SingleModel :
public class SingleModel {
//创建 SingleModel 的一个对象
private static SingleModel instance = new SingleModel();
//让构造函数为 private,这样该类就不会被实例化
private SingleModel(){}
//获取唯一可用的对象
public static SingleModel getInstance(){
return instance;
}
public void useMessage(){
System.out.println("Single Model!");
}
}
测试:
public class DemoTest {
/****
* 单例模式测试
*/
@Test
public void testSingleModel(){
//不合法的构造函数
//编译时错误:构造函数 SingleModel() 是不可见的
//SingleModel singleModel = new SingleModel();
//获取唯一可用的对象
SingleModel singleModel1 = SingleModel.getInstance();
SingleModel singleModel2 = SingleModel.getInstance();
//显示消息
singleModel1.useMessage();
//创建的2个对象是同一个对象
System.out.println(singleModel1 == singleModel2);
}
}
输入结果如下:
Single Model!
true
我们测试创建 10 万个对象,用单例模式创建,仅占内存: 104 字节,而如果用传统方式创建 10 万个对
象,占内存大小为 2826904 字节。

1.2 扩展

单例模式有多种创建方式,刚才创建方式没有特别的问题,但是程序启动就需要创建对象,不管你用不
用到对象,都会创建对象,都会消耗一定内存。因此在单例的创建上出现了多种方式。
懒汉式:
1 、延迟加载创建,也就是用到对象的时候,才会创建
2 、线程安全问题需要手动处理 ( 不添加同步方法,线程不安全,添加了同步方法,效率低 )
3 、实现容易
案例如下: SingleModel1
 public class SingleModel1 {private static SingleModel1 instance;private SingleModel1(){}public static SingleModel1 getInstance(){if(instance == null){instance = new SingleModel1();}return instance;}}
如果在创建对象实例的方法上添加同步 synchronized , 但是每次 get 获取对象都必须排队竞争,效率极
低,代码如下:
添加同步会解决多线程安全的问题但是会明显的降低获取对象实例的效率。
public static synchronized SingleModel1 getInstance() {if (instance == null){instance = new SingleModel1();}return instance;}
双重校验锁: SingleModel2
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class SingleModel2 {//不实例化private static SingleModel2 instance;//让构造函数为 private,这样该类就不会被实例化private SingleModel2(){}//获取唯一可用的对象public static SingleModel2 getInstance(){
//instance为空的时候才创建对象if(instance==null){
//同步锁,效率比懒汉式高synchronized (SingleModel2.class){
//这里需要判断第2次为空if(instance==null){instance = new SingleModel2();}}}return instance;}public void useMessage(){System.out.println("Single Model!");}}
指令重排问题
对象创建,一般正确流程如下:
  1. 申请内存空间
  2. 创建并初始化对象
  3. 将变量指向申请的内存空间地址
但其实在对象创建的时候,也有可能发生 指令重排问题,也就是上面流程会被打乱:
  1. 申请内存空间
  2. 将变量指向申请的内存空间地址 //这一步后,变量不再为null,但是初始化其实并没完成
  3. 创建并初始化对象
如果是这样的话,双检锁在多线程情况下也会出现问题,需要添加 volatile 属性,该属性能防止指令
重排,代码如下:
    public class SingleModel2 {//不实例化private static volatile SingleModel2 instance;//让构造函数为 private,这样该类就不会被实例化private SingleModel2(){}//获取唯一可用的对象public static SingleModel2 getInstance(){
//instance为空的时候才创建对象if(instance==null){
//同步锁,效率比懒汉式高synchronized (SingleModel2.class){
//这里需要判断第2次为空if(instance==null){instance = new SingleModel2();}}}return instance;}public void useMessage(){System.out.println("Single Model!");}}

1.3 单例模式特点

  1. 单例类只能有一个实例。 A a = new A()
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

1.4单例模式优点:

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
  2. 避免对资源的多重占用(比如写文件操作)。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux - 探秘/proc/sys/net/ipv4/ip_local_port_range
  • 嵌入式Linux电池管理(TODO)
  • 【SpringCloud】微服务架构演进与Spring Cloud简介
  • EasyExcel 动态表头+表头合并
  • C语言基础——⑩③数据结构——②栈和队列
  • (不用互三)AI绘画工具应该如何选择
  • C语言 | Leetcode C语言题解之第394题字符串解码
  • Spring Framework 学习总结博客
  • 快速入门编写一个Java程序
  • 【mysql】mysql之主从部署以及介绍
  • 无头服务(Headless Service)
  • gen_server补充基础学习
  • linux cmake版本升级教程(Centos7)
  • Vue3:el-table实现日期的格式化
  • 使用python绘制森林图的教程
  • 【Linux系统编程】快速查找errno错误码信息
  • export和import的用法总结
  • github从入门到放弃(1)
  • MaxCompute访问TableStore(OTS) 数据
  • nfs客户端进程变D,延伸linux的lock
  • Python语法速览与机器学习开发环境搭建
  • 从setTimeout-setInterval看JS线程
  • 分布式事物理论与实践
  • 来,膜拜下android roadmap,强大的执行力
  • 力扣(LeetCode)357
  • 使用 QuickBI 搭建酷炫可视化分析
  • 微信小程序设置上一页数据
  • 无服务器化是企业 IT 架构的未来吗?
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 追踪解析 FutureTask 源码
  • hi-nginx-1.3.4编译安装
  • 如何正确理解,内页权重高于首页?
  • 选择阿里云数据库HBase版十大理由
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #{}和${}的区别?
  • #define、const、typedef的差别
  • #QT(串口助手-界面)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (2)nginx 安装、启停
  • (42)STM32——LCD显示屏实验笔记
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (C语言)二分查找 超详细
  • (Git) gitignore基础使用
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (面试必看!)锁策略
  • (三)Kafka 监控之 Streams 监控(Streams Monitoring)和其他
  • (四)js前端开发中设计模式之工厂方法模式
  • (学习总结16)C++模版2
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)Oracle存储过程编写经验和优化措施
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .gitignore文件设置了忽略但不生效
  • .mysql secret在哪_MYSQL基本操作(上)