浅谈单例模式

news/2025/1/7 22:13:01/
  • 饿汉式
  • 懒汉式/Double check(双重检索)
  • 静态内部类
  • 枚举单例
 饿汉式
    private static final DispatchSingleton instence = new DispatchSingleton();public static DispatchSingleton getInstence() {return instence;}

饿汉式是在jvm加载这个单例类的时候,就会初始化这个类中的实例,在使用单例中的实例时直接拿来使用就好,因为加载这个类的时候就已经完成初始化,并且由于是已经加载好的单例实例因此是线程安全的,并发获取的情况下不会有问题,是一种可投入使用的可靠单例。

优点:使用起来效率高、线程安全

缺点:由于jvm在加载单例类的时候需要初始化单例实例,因此在加载单例的时候针对jvm内存不够友好。

懒汉式
    private static DispatchSingleton mSluggardInstence;public static DispatchSingleton getSluggardInstence(){if (mSluggardInstence==null){mSluggardInstence=new DispatchSingleton();}return mSluggardInstence;}

最简单的懒汉式,核心思想就是弥补饿汉式的缺点,在jvm加载单例类的时候不去初始化实例,而是在第一次获取实例的时候再去初始化实例。但是这样理论完美的单例在使用的时候有一个致命的缺点,在多线程使用的情况下,有时会出现不同线程从单例实例中获取不同的实体。针对多线程环境中并不可靠。

优点:针对jvm内存比较友好,实现了实例的懒加载。

缺点:多线程环境下不安全,会出现不同线程从单例实例中获取不同的实体的情况。

    private static volatile DispatchSingleton mSluggardInstence;public static DispatchSingleton getSluggardInstence() {if (mSluggardInstence == null) {synchronized (DispatchSingleton.class) {if (mSluggardInstence == null) {mSluggardInstence = new DispatchSingleton();}}}return mSluggardInstence;}
synchronized

 针对懒汉式的这种线程不安全的现:在单例初始化时,多线程存在创建多次实例的风险

锁的粒度",锁的粒度: 粗和细加锁代码涉及到的范围,加锁代码的范围越大,认为锁的粒度越粗范围越小,则认为粒度越细

所以synchronized锁住获取实例的整个方法也可以解决问题,且在并发获取单例实例的时候会有性能问题。故此减小锁的粒度。

volatile  

在于jdk1.5开始针对volatile进行了增强,因为Volatile会禁止指令重排序

静态内部类
    private static class Holder{private static DispatchSingleton singleton = new DispatchSingleton();}public static DispatchSingleton getHolderInstence() {return Holder.singleton;}

静态内部类的优点是:外部类加载时并不会立即加载内部类,内部类不被加载就不去初始化实例,因此实现了懒加载。当DispatchSingleton第一次被加载时,并不需要去加载内部类Holder,只有当getInstance()方法第一次被调用时,才会导致虚拟机加载Holer类菜会去初始化StaticSingle实例。这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

枚举单例

以上解决了效率或者懒加载以及线程安全的问题,但是它们都有两个共同的缺点: 序列化可能会破坏单例模式

    public enum DispatchSingle {INSTANCE;public void doSomething(){}}

  • 自由序列化
  • 保证只有一个实例
  • 线程安全
  • 与静态内部类的区别
    • 枚举单例为直接加载,静态内部类为懒加载
    • 两者相比较,静态内部类比较节省资源开销

我们也可以像常规类一样编写enum类,为其添加变量和方法,访问方式也更简单,使用DispatchSingle .INSTANCE进行访问,这样也就避免调用getInstance方法,更重要的是使用枚举单例的写法,我们完全不用考虑序列化和反射的问题。枚举序列化是由jvm保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的。


http://www.ppmy.cn/news/1164787.html

相关文章

Go语言入门心法(六): HTTP面向客户端|服务端编程

Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 Go语言入门心法(四): 异常体系 Go语言入门心法(五): 函数 一:go语言面向web编程认知 Go语言的最大优势在于并发与性能,其性能可以媲美C和C,并发在网络编程中更是至关重要 使用http发送请…

树莓派+RTL-SDR 搭建APRS iGATE

最近买了个FT-5DR,准备玩APRS,但是长沙的iGATE少的可怜,为了让自己的呼号显示到APRS.TV,只能自己折腾一个iGATE了。 淘宝上有现成的产品,不过要花几百块钱,有点划不来,本着业余无线电不怕折腾的…

MVC netbeans数据库操作注意事项

前端通过Form传递到后端Servlet注意事项 MVC是Mode View Control三层架构模式 Mode封装了数据库实体类 View封装了前端界面 Control通过Servlet实现 在数据库方面需要注意: 首先是jdbc封装 通过 username pssword driver,url进行封装。 class.forname加载驱…

Milk-V Duo快速上手

前言 (1)此系列文章是跟着汪辰老师的RISC-V课程所记录的学习笔记。 (2)该课程相关代码gitee链接; (3)PLCT实验室实习生长期招聘:招聘信息链接 (4)最近实习需要…

Android高版本读取沙盒目录apk解析安装失败解决方案

bug场景: 应用内升级下载apk完成后安装,vivo(Android13)手机会报解析包错误,7.0及以上的手机是没问题的。开始以为是v1,v2签名问题导致的,但是我用浏览器下载下来的安装包是能够正确安装的。排除v1,v2签名的…

python setup error: [WinError 2] 系统找不到指定的文件

python setup error: [WinError 2] 系统找不到指定的文件 原因还未找到, 以下是网友的方法,测试没成功。 2、编译源码 需要的工具Visual C 2015 build tools(如果下载过完整的VS就不用管) cd 到PythonAPI文件下然后执行以下代码 # install pycocot…

grpc实现跨语言(go与java)服务通信

Golang微服务实战:使用gRPC实现跨语言通信!随着微服务架构的发展,越来越多的企业开始采用微服务架构来构建分布式系统。在微服务架构中,服务之间的通信是非常重要的。而gRPC作为一种高效、跨平台、跨语言的RPC框架,成为…

GB/T 26538-2011 烧结保温砖和保温砌块检测

烧结保温砖和烧结保温砌块是指经焙烧而成主要用于建筑物围护结构保温隔热的砌块和砖,其外形多为直角六面体,具有防火保温隔热等性能。 GB/T 26538-2011 烧结保温砖和保温砌块测试: 测试项目 测试方法 外观 GB/T 2542 尺寸 GB/T 2542 抗…