详解:单例模式中的饿汉式和懒汉式

ops/2024/10/30 10:53:05/

        单例模式是一种常用的设计模式,其目的是确保一个类只有一个实例(对象),并提供一个全局访问点单例模式有两种常见的实现方式:饿汉式和懒汉式。

一、饿汉式

        饿汉式在类加载时就完成了实例化。因为类加载是线程安全的,所以在多线程环境下也是安全的。这种方式比较简单,但是由于实例在类加载时就创建,即使没有被使用,也会占用内存资源。

步骤:

1.私有化构造函数

解释:当私有化构造函数那么其他类就不能创建该类的对象,相当于该类的一切非静态的成员在其他类中都访问不了了!!!当你使用new创建对象时会调用其构造方法,因为构造函数私有化了,所以创建不了对象,创建不了对象相当于一切非静态的成员在其他类中都访问不了。

2.创建私有的静态类的对象

解释:为什么是私有的?防止其他类直接调用对象从而破坏单例的唯一性。为什么是静态的?如果不是静态的属性,那么其他类无法创建对象进行访问。

3.创建公共的静态get方法获取静态类的对象!!!

解释:该操作类似于封装私有的成员变量然后只能通过公共的set和get方法来获取,但是改操作是一个静态的方法,静态的方法只能调用静态的成员变量不能直接调用非静态的成员。

代码示例:

public class Person {private String name;// 在类加载时就创建实例private static Person person = new Person("小明");// 私有构造函数,防止外部实例化private Person(String name){this.name=name;}// 提供全局访问点  public static Person getInstance(){return person;}@Overridepublic String toString() {return name;}
}
class Test{public static void main(String[] args) {Person person1 = Person.getInstance();Person person2 = Person.getInstance();System.out.println(person1);System.out.println(person2);System.out.println(person1==person2);}
}

结果如下:

小明
小明
true

         解释:这段代码,我们只能通过静态的getInstance()方法来获取Person对象,并且只能获取一个对象,因为在其他类(比如Test类)创建不了Person对象而只能获取一个Person对象,当我们再次调用静态的getInstance()方法来获取Person对象时,本质上是获取同一个对象,所以通过“==”进行比较得到的结果是true。

疑问1:为什么输出的是小明?

答:因为Person类重写了toString方法。

疑问2:为什么name属性不是静态的属性?

答:在你不需要调用name属性时不需要写成静态的属性。

疑问3:为什么实例(对象)在类加载时就创建?

答:因为在类加载时会进行静态属性的初始化和执行静态代码块。

参考文献:类什么时候加载?-CSDN博客

优点:

  • 线程安全:因为实例在类加载时就创建,天然线程安全。
  • 实现简单:代码量少,容易理解。

缺点:

  • 资源浪费:如果实例从未被使用,仍然会占用内存。

二、懒汉式

        懒汉式在第一次调用getInstance()方法时才创建实例。这种方式延迟了实例化,节省了资源,但需要考虑线程安全问题。

代码如下:

public class Person {private String name;// 声明实例,但不立即创建  private static Person person;// 私有构造函数,防止外部实例化private Person(String name){this.name=name;}// 提供全局访问点但非线程安全public static Person getInstance(){if (person==null){person = new Person("小明");}return person;}@Overridepublic String toString() {return name;}
}
class Test{public static void main(String[] args) {Person person1 = Person.getInstance();Person person2 = Person.getInstance();System.out.println(person1);System.out.println(person2);System.out.println(person1==person2);}
}

结果如下(和饿汉式代码的结果一样):

小明
小明
true

解释:与饿汉式的区别是懒汉式在第一次调用getInstance()方法时才创建实例并不是类加载时就创建实例对象,创建实例对象时首先判断对象是否存在,不存在则创建对象,存在则返回已存在的对象。

线程安全问题

        在懒汉式单例模式中,如果多个线程同时调用getInstance()方法,并且此时实例尚未创建(即instance变量为null),那么这些线程都可能进入创建实例的代码块。如果没有适当的同步机制,就可能导致多个线程同时创建实例,从而违反单例模式的原则。

优点:

  • 延迟实例化,节省资源。

缺点:

  • 实现复杂:需要考虑线程安全问题。

        饿汉式和懒汉式的选择取决于具体的应用场景。如果单例对象较大且创建过程耗时,或者类加载时间较长,可以考虑使用懒汉式。如果单例对象较小且创建过程简单,或者类加载时间可以接受,可以考虑使用饿汉式。同时,懒汉式需要考虑线程安全问题,而饿汉式则不需要。


http://www.ppmy.cn/ops/129557.html

相关文章

设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

#1024程序员节|征文# 4.1 适配器模式 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。结构性模式的分类: ​ 类结构型模式关心类的组合,由多个类…

C语言中的位操作

第一章 变量某位赋值与连续赋值 寄存器 | 值 //例如&#xff1a;a 1000 0011b a | (1<<2) //a 1000 0111 b 单独赋值 a | (3<<2*2) // 1011 0011b 连续赋值 第二章 变量某位清零与连续清零 寄存器 & ~&#xff08;&#xff09; 值 //例子&#xff1a;a …

MATLAB车道检测与跟踪

读了车道检测这个论文&#xff0c;我理解了利用matlab对车道识别算法进行仿真研究&#xff0c;从仿真的结果中提出具有一定实时性鲁棒性的识别方法。车道检测是智能车辆发展的智能因素。近年来对这项目的研究都是针对特定的环境和道路状况给出了不同的解决方案。近年来,自主驾驶…

NVR小程序接入平台/设备EasyNVR多个NVR同时管理视频监控新选择

在数字化转型的浪潮中&#xff0c;视频监控作为安防领域的核心组成部分&#xff0c;正经历着前所未有的技术革新。随着技术的不断进步和应用场景的不断拓展&#xff0c;视频监控系统的兼容性、稳定性以及安全性成为了用户关注的焦点。NVR小程序接入平台/设备EasyNVR&#xff0c…

【本科毕业设计】基于单片机的智能家居防火防盗报警系统

基于单片机的智能家居防火防盗报警系统 源码下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系统框图 3…

核心HTML5/CSS3基础面试题

HTML5/CSS3 高频经典面试题 汇总了 2023 年各互联网大厂以及中小型创业公司基础阶段的最新高频面试题 HTML/HTML5 标签 Interview questions 1、说说你对 HTML 语义化的理解 ?HTML5 新增了哪些语义化标签 ?(字节、百度,阿里,腾讯、京东,小米) 2、DOCTYPE 是干嘛的,…

一篇文章入门傅里叶变换

文章目录 傅里叶变换欧拉公式傅里叶变换绕圈记录法质心记录法傅里叶变换公式第一步&#xff1a;旋转的表示第二步&#xff1a;缠绕的表示第三步&#xff1a;质心的表示最终步&#xff1a;整理积分限和系数 参考文献 傅里叶变换 在学习傅里叶变换之前&#xff0c;我们先来了解一…

ubuntu df -h分配的磁盘空间小于物理磁盘

1. 检查卷组的可用空间 运行以下命令查看卷组的大小和空闲空间&#xff1a; vgdisplay或者&#xff1a; sudo vgs看一下是否有多余的空间未分配给逻辑卷。 2. 扩展逻辑卷 假设 ubuntu--vg-ubuntu--lv 是你想扩展的逻辑卷名称&#xff0c;运行以下命令将空闲空间分配到该逻…