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

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

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

一、饿汉式

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

步骤:

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;
    }

    @Override
    public 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;
    }

    @Override
    public 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.kler.cn/a/372636.html

相关文章:

  • Face2face:非深度学习时代如何进行实时的三维人脸重建
  • Low-Level 大一统:如何使用Diffusion Models完成视频超分、去雨、去雾、降噪等所有Low-Level 任务?
  • 脚本工具:PYTHON
  • 力扣11-最后一个单词的长度
  • Matlab总提示内存不够用,明明小于电脑内存
  • CSS实现实现票据效果 mask与切图方式
  • lego-loam mapOptmization 源码注释(一)
  • Lua语法基础全面剖析(中篇)
  • uni-app应用级生命周期和页面级生命周期
  • huggingface之tokenization基础结构Trie-代码解读
  • 【缓存与加速技术实践】Redis 主从复制
  • 银河麒麟v10安装Anaconda(python大蟒蛇)+pycharm安装
  • AJAX和JSON
  • K8S 容器可视化管理工具-kuboard 监控管理工具搭建
  • 操作数据表
  • 【蓝桥杯选拔赛真题81】python矩形数量 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
  • C++ 中回调函数的实现方式-函数指针
  • ICT网络赛道安全考点知识总结1
  • 笔记整理—linux驱动开发部分(2)模块信息与编译
  • 记录一次查询优化
  • 关于Mac打包ipa的配置小结
  • Hyperledger Fabric有那些核心技术,和其他区块链对比Hyperledger Fabric有那些优势
  • Spring Boot 实现文件分片上传和下载
  • 运维端口号详解(Detailed Explanation of Operation and Maintenance Port Numbers)
  • 高效MySQL缓存策略
  • C++(运算符重载)