首页 > 其他分享 >创建型模式--单例模式

创建型模式--单例模式

时间:2024-04-09 23:23:20浏览次数:70  
标签:饿汉 -- 创建 模式 对象 枚举 单例 序列化

创建型模式--单例模式

简介:单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象(例如数据库连接池)。

单例模式有两种类型:

  • 懒汉式:在真正需要使用对象时才去创建该单例类对象。
  • 饿汉式:在类加载时已经创建好该单例对象,等待被程序使用。

懒汉式创建单例对象

懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象。,否则则先执行实例化操作。因为需要两次判空,且对类对象加锁,该懒汉式写法也被称为:Double Check(双重校验) + Lock(加锁)。

public class LazySingleton {
    private static volatile LazySingleton instance; // 使用volatile关键字确保多线程环境下的可见性

    private LazySingleton() {
        // 私有构造函数,避免外部类直接实例化
    }

    public static LazySingleton getInstance() {
        if (instance == null) { // 第一次判空
            synchronized (LazySingleton.class) { // 加锁
                if (instance == null) { // 第二次判空
                    instance = new LazySingleton(); // 实例化操作
                }
            }
        }
        return instance;
    }
}

饿汉式创建单例对象

饿汉式在类加载时已经创建好该对象,在程序调用时直接返回该单例对象即可,即我们在编码时就已经指明了要马上创建这个对象,不需要等到被调用时再去创建。
关于类加载,我们目前可以简单认为在程序启动时,这个单例对象就已经创建好了。

public class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton(); // 在类加载时就创建实例

    private EagerSingleton() {
        // 私有构造函数,避免外部类直接实例化
    }

    public static EagerSingleton getInstance() {
        return instance;
    }
}

破坏懒汉式单例与饿汉式单例

无论是完美的懒汉式还是饿汉式,终究敌不过反射和序列化,它们俩都可以把单例对象破坏掉(产生多个对象)。

枚举实现单例(Java)

使用枚举实现单例模式的优势在哪里?

  • 优势1:代码对比饿汉式与懒汉式来说,更加地简洁。
  • 优势2:它不需要做任何额外的操作去保证对象单一性与线程安全性。
  • 优势3:使用枚举可以防止调用者使用反射、序列化与反序列化机制强制生成多个单例对象,破坏单例模式。
    • 防反射
      image
      枚举类默认继承了 Enum 类,在利用反射调用 newInstance() 时,会判断该类是否是一个枚举类,如果是,则抛出异常。
    • 防止反序列化创建多个枚举对象
      image
      在读入 Singleton 对象时,每个枚举类型和枚举名字都是唯一的,所以在序列化时,仅仅只是对枚举的类型和变量名输出到文件中,在读入文件反序列化成对象时,利用 Enum 类的 valueOf(String name) 方法根据变量的名字查找对应的枚举对象。Java会根据枚举实例的名称来匹配对应的枚举实例。
      所以,在序列化和反序列化的过程中,只是写出和读入了枚举类型和名字,没有任何关于对象的操作。

小总结:

  • Enum 类内部使用 Enum 类型判定防止通过反射创建多个对象
  • Enum 类通过写出(读入)对象类型和枚举名字将对象序列化(反序列化),通过 valueOf() 方法匹配枚举名找到内存中的唯一的对象实例,防止通过反序列化构造多个对象
  • 枚举类不需要关注线程安全、破坏单例和性能问题,因为其创建对象的时机与饿汉式单例有异曲同工之妙。

总结

  • 单例模式常见的写法有两种:懒汉式、饿汉式。
  • 懒汉式:在需要用到对象时才实例化对象,正确的实现方式是:Double Check + Lock,解决了并发安全和性能低下问题。
  • 饿汉式:在类加载时已经创建好该单例对象,在获取单例对象时直接返回对象即可,不会存在并发安全和性能问题。
  • 在开发中如果对内存要求非常高,那么使用懒汉式写法,可以在特定时候才创建该对象。
  • 如果对内存要求不高使用饿汉式写法,因为简单不易出错,且没有任何并发安全和性能问题。
  • 为了防止多线程环境下,因为指令重排序导致变量报 NPE,需要在单例对象上添加 volatile 关键字防止指令重排序
  • 最优雅的实现方式是使用枚举,其代码精简,没有线程安全问题,且 Enum 类内部防止反射和反序列化时破坏单例(Java)。

标签:饿汉,--,创建,模式,对象,枚举,单例,序列化
From: https://www.cnblogs.com/NorthnightX/p/18125091

相关文章

  • 你真会判断DataGuard的延迟吗?
    这是一个比较细节的知识点,但必须要理解这个才能准确判断OracleADG的延迟情况。以前做运维工作时,记得是要同时重点关注v$dataguard_stats视图中的几个字段的值,分别是:NAME、VALUE、TIME_COMPUTED、DATUM_TIME。本文先不考虑v$dataguard_stats视图没有数值显示的特殊情况,只针对当v......
  • 协程杂记
    协程杂记协程是什么协程是一种协作式多任务模型,不同于线程的抢占式多任务模型。协程是由程序员自己控制的,可以在任意时刻挂起或者恢复一个协程,更适合于用来实现彼此熟悉的程序组件。在通常使用线程的情景中,负责处理不同任务的线程之间存在着数据竞争,使用加锁可以解决问题,但其实......
  • 组合数学
    生成函数使用母函数的方法求谢列数列的通项\(a_n.\)\((1)a_0=2,a_1=5,a_{n+2}=3a_{n+1}-2a_n(n=0,1,2,\cdots);\)解:设\(f(x)=a_0+a_1x+a_2x^2+a_3x^3+\cdots.\)则:\(\qquad-3f(x)=-3a_0x-3a_1x^2-3a_2x^3-\cdots.\)\(\quad\quad\qquad\qquad2f(x)=+2a_0x^2+2a_1x^3+2a_2x......
  • MongoDB的一次奇妙查询
    这段时间遇到了一个业务需求,我有一些关于书籍的文档数据存储在MongoDB数据中,然后在修复数据之后,需要用一个查询去验证更新是否成功。书籍数据大概长这个样子:{"books":[{"name":"UbuntuMeta","sku_id":"101","price":30.5},{&q......
  • c#重载
    usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespace方法重载{classarea{publicstaticdoubleAREA(doubler){doublepi=3.14,j=0;j=r*r*pi;returnj;}......
  • C. Rings
    原题链接题解不仅要学会怎么打cf,还要学会怎么解决问题:把条件写下来,对着条件写,然后对着程序在脑海中充分模拟code#include<bits/stdc++.h>usingnamespacestd;chars[20005];intmain(){intt;cin>>t;while(t--){intn;cin>>n;......
  • 最大连续子数组和的实现
    题目:最大连续子数组和求解问题一、背景:问题:给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为:Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n例如,当(a[1],a[2],a[3......
  • 了解python的装饰器特性
    装饰器相当于一个装饰,不修改函数原本内容,只是增添内容defmy_decorator(func):defwarpper():print("有函数要执行了")func()print("有函数执行完毕")returnwarpper@my_decoratordefsay_hello():print("hello")say_hello()......
  • 协议
    协议协议就是计算机与计算机之间通过网络实现通信时事先达成的一种“约定”计算机之间必须使用相同的协议才能通信网络体系结构不同网络体系中,协议不同TCP/IP:IP,TCP,HTTP等IPX/SPX(Novell):IPX,SPX,NPC等AppleTalk(Apple):ADP,AEP等协议的标准化由于不同厂商有各自......
  • HarmonyOS-基础之@Watch监听、@ObjectLink和@Observed
    1、Watch监听类似Vue中的数据监听,监听的数据发生了变化-->做啥事情父组件importChild07from'../components/Child07'@Entry@ComponentstructWatchExample{//watch可以监听组件状态State|Link|Provide......@State@Watch('update')obj:{a:n......