Java中的单例模式(如果想知道Java中有关单例模式的知识,那么只看这一篇就 ...

打印 上一主题 下一主题

主题 853|帖子 853|积分 2559

        媒介:单例模式(Singleton Pattern)是一种确保类仅有一个实例,并提供全局访问点的筹划模式,它常用于数据库连接、日志管理等必要共享资源的场景,通过制止重复创建实例,进步资源使用率。

   

  ✨✨✨这里是秋刀鱼不做梦的BLOG
  ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客
  在正式开始讲解之前,先让我们看一下本文大致的讲解内容:

目录
1.单例模式简介和应用场景
        (1)单例模式的简介
        (2)单例模式的应用场景
2.饿汉模式
3.懒汉模式 - 单线程版
4.懒汉模式 - 多线程版
5.懒汉模式 - 多线程版(改进)


1.单例模式简介和应用场景

        (1)单例模式的简介

        在开始学习如何使用单例模式之前,先让我们了解一下什么是单例模式:
           单例模式(Singleton Pattern)是一种创建型筹划模式,它确保在应用程序的整个生命周期中,某个类只有一个实例存在,并提供一个全局的访问点来使用这个实例。
          想象我们要建立一个管理系统,用于控制系统资源(比如数据库连接、文件读写等),如果每个操纵都创建新的实例,将导致资源的浪费,而单例模式的出现正是为了节约资源,并确保同一时间内应用中只存在一个对象实例。

        (2)单例模式的应用场景

        在了解完了什么是单例模式之后,再让我们了解一下单例模式的应用场景吧,以下为单例模式的应用场景:
   

  • 数据库连接池:只需一个连接池对象,重复使用已存在的数据库连接。
  • 设置文件读取:设置文件一般是全局的,所以只必要一个设置文件读取对象。
  • 线程池:为了高效管理线程,确保线程资源的有效使用。
  • 日志类:使用单例确保全局只有一个日志记载器,从而统一管理日志输出。
          至此,我们就大致的了解了单例模式是什么和有什么用处了!!!

        常见的单例模式实现包罗饿汉模式懒汉模式,前者实例初始化较早,后者实例初始化较晚,但使用了“延迟加载”机制,两种方式在性能、安全性等方面各有优缺点,那么接下来就让我们一一进行讲解。

2.饿汉模式

        在学习如何使用饿汉模式之前,先让我们了解一下什么是饿汉模式。
原理及实现:
           饿汉模式在类加载时就创建实例,无论程序是否必要,实例都会被提前初始化。此模式的焦点是“在类加载时创建实例”,也因此得名“饿汉”模式。由于类加载只执行一次,饿汉模式自然是线程安全的,不会引发并发标题。
  饿汉模式代码示例:
  1. public class Singleton {
  2.     // 静态成员变量,类加载时创建单例实例
  3.     private static final Singleton instance = new Singleton();
  4.     // 私有化构造方法,防止外部创建对象
  5.     private Singleton() {}
  6.     // 静态方法,提供全局访问单例实例的入口
  7.     public static Singleton getInstance() {
  8.         return instance;
  9.     }
  10. }
复制代码
这里我们对上述的代码进行分析讲解,以便于读者更好的理解:
代码分析:
   

  • instance 是一个静态变量,属于 Singleton 类,并在类加载时初始化。
  • 将构造方法 Singleton() 设置为私有,制止外部通过构造方法创建对象。
  • getInstance 方法为用户提供全局访问点,始终返回同一个实例。
  优缺点分析:
   

  • 优点:实现简单,类加载时主动创建实例,自然具备线程安全性。
  • 缺点:纵然实例未被使用,仍会被创建,浪费内存资源,不适合大对象的延迟加载需求。
          通过上述的讲解,我们可以了解到饿汉模式适合对资源消耗不高的情况,大概单例对象必然会被使用的场景,这样我们就大致的了解了什么是饿汉模式并且会使用它了。

3.懒汉模式 - 单线程版

        了解完了饿汉模式之后,在让我们看一下懒汉模式,起首先让我们讲解一下懒汉模式 - 单线程版:
原理及实现:
           懒汉模式接纳“延迟加载”的方式,即实例只在第一次使用时才进行创建,而不是类加载时初始化。
          这种实现方式的好处是仅在必要时才创建实例,从而节省资源,但在单线程的场景中,这种方式没有标题,但在多线程情况下可能导致多个线程同时创建实例,违背了单例模式的初志。
懒汉模式 - 单线程版代码代码示例:
  1. public class Singleton {
  2.     // 静态成员变量,初始化为 null
  3.     private static Singleton instance = null;
  4.     // 私有化构造方法,防止外部创建对象
  5.     private Singleton() {}
  6.     // 静态方法,在首次调用时创建实例
  7.     public static Singleton getInstance() {
  8.         if (instance == null) {
  9.             instance = new Singleton(); // 只有首次调用才会创建实例
  10.         }
  11.         return instance;
  12.     }
  13. }
复制代码
和上述的饿汉模式一样,这里我们对上述的代码进行分析讲解,以便于读者更好的理解:
代码分析:
   

  • instance 被初始化为 null,意味着在初次调用 getInstance 方法之前不会创建实例。
  • getInstance 方法在 instance 为 null 时创建单例对象。
  优缺点分析:
   

  • 优点:支持延迟加载,仅在初次使用时才初始化,节省内存。
  • 缺点:无法应对多线程并发场景,多个线程同时访问 getInstance 时可能创建多个实例,违背单例的焦点思想。
          通过上述的讲解,我们可以了解到单线程懒汉模式仅适用于单线程情况或不涉及并发访问的单例需求,适用于较小的单线程应用,这样我们就大致的了解了懒汉模式 - 单线程版啦。

4.懒汉模式 - 多线程版

        了解完懒汉模式 - 单线程版之后,让我们学习一下懒汉模式 - 多线程版:
原理及实现:
           为了解决懒汉模式在多线程情况下的并发标题,可以在 getInstance 方法上添加 synchronized 关键字,确保同一时间只有一个线程可以调用 getInstance 方法。
  固然这种方式解决了线程安全标题,但同步操纵会带来性能开销,特别是在高并发情况下
懒汉模式 - 多线程版代码代码示例:
  1. public class Singleton {
  2.     private static Singleton instance = null;
  3.     private Singleton() {}
  4.     // synchronized 保证线程安全,但会带来性能开销
  5.     public static synchronized Singleton getInstance() {
  6.         if (instance == null) {
  7.             instance = new Singleton(); // 仅首次调用时创建实例
  8.         }
  9.         return instance;
  10.     }
  11. }
复制代码
这里我们还是对上述的代码进行分析讲解,以便于读者更好的理解:
代码分析:
   

  • synchronized 关键字包管 getInstance 方法的同步性,制止多个线程同时调用时创建多个实例。
  • 每次调用 getInstance 都会锁定方法,包管线程安全,但影响了性能。
  优缺点分析:
   

  • 优点:线程安全,确保在多线程情况下只会创建一个实例。
  • 缺点:同步带来的性能开销,使得每次调用 getInstance 都必要获取锁,性能较低。
          而这种方式适合低并发场景,不发起用于频繁访问的单例模式实现。

5.懒汉模式 - 多线程版(改进)

        在上述的懒汉模式 - 多线程版中,其实隐藏着许许多多的标题,这里我们对上述隐藏的标题进行一一解决:
改进一:
        为进步性能,我们可以接纳双重查抄锁定(Double-Check Locking, DCL)来减少同步开销。双重查抄锁定的思路是:在同步代码块的外部添加一个 if 判断,以减少不须要的同步操纵。通过双重查抄锁定,可以确保只在初次创建实例时进行同步,后续调用直接返回已有实例,制止性能下降。
改进二:
        为了包管内存的可见性并防止指令重排序,可以在 instance 前加上 volatile 关键字。

改进步骤:
        第一步:添加外层 if 判断 起首在 synchronized 代码块外添加 if 判断,减少不须要的同步操纵。
  1. public static Singleton getInstance() {
  2.     if (instance == null) { // 第一次检查
  3.         synchronized (Singleton.class) {
  4.             if (instance == null) { // 第二次检查
  5.                 instance = new Singleton();
  6.             }
  7.         }
  8.     }
  9.     return instance;
  10. }
复制代码
        第二步:引入 volatile 关键字 添加 volatile 关键字来确保实例在不同线程下的内存可见性,制止因指令重排序导致的标题。
  1. public class Singleton {
  2.     private static volatile Singleton instance = null; // 确保多线程间的可见性
  3.     private Singleton() {}
  4.     public static Singleton getInstance() {
  5.         if (instance == null) { // 第一次检查
  6.             synchronized (Singleton.class) {
  7.                 if (instance == null) { // 第二次检查
  8.                     instance = new Singleton();
  9.                 }
  10.             }
  11.         }
  12.         return instance;
  13.     }
  14. }
复制代码
        同样我们对上述的代码进行分析讲解,以便于读者更好的理解:

代码分析:
   

  • 初次调用时,外层的 if 判断 instance == null,制止了每次调用都进行同步操纵,进步了性能。
  • 在同步代码块内部进行二次查抄,确保在多线程并发的情况下也不会重复创建实例。
  • volatile 关键字制止了指令重排序标题,确保了多个线程能够精确地读取到最新的 instance 值。
  优缺点分析:
   

  • 优点:线程安全,支持高并发场景,并减少了不须要的同步操纵,进步性能。
  • 缺点:相较于饿汉模式,代码实现更为复杂,增加了理解和维护难度。
          通过上述的改进之后,使得懒汉模式适应高并发场景,特别是实例初始化资源较大的情况。
——至此我们就了解了所以有关单例模式的内容了!!!


以上就是本篇文章的全部内容了~~~


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

何小豆儿在此

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表