【单例深思】Java 单例模式全解

【单例深思】枚举实现单例原理 https://blog.youkuaiyun.com/gavin_dyson/article/details/70832185 ... 阅读详情
什么是单例模式?

单例模式 是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例,并提供一个访问它的全局访问点。

单例模式的用途?

用于创建只需要一个实例的场景。

怎么实现单例模式?

单例模式的实现中有几个共同特点:

  1. 使用 private 声明类构造函数,这样就不能通过new 声明这个类的对象了,防止形成多个实例。
  2. 使用 private 声明类的单实例,防止外部直接访问。
  3. 提供唯一的全局访问方法,如getSignleton()来访问单实例。

单例模式性能的评价标准:
  1. 延迟加载
  2. 线程安全
  3. 并发访问性能
  4. 内存可见性
  5. 使用通用性
  6. 序列化不破坏单实例


Java中实现单例模式有多种方法,下面我们一一介绍:

  1. 饿汉式

public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {}
    public static Singleton getSignleton(){
        return singleton;
    }
}  

顾名思义,这个实现就像是饥不择食的饿汉,在类装载时就忍不住实例化了。

非延迟加载:这种方式单实例  singleton  在类装载时就实例化,由于在静态成员singleton 使用了new 会在类加载时就初始化,这时候初始化 singleton 没有延迟加载的效果,如果这个单例类没有被用到,那么就会造成资源浪费。
线程安全: 类装载时实例化,一个类只会有同一类加载器加载一次,由JVM保证线程安全。


    2. 懒汉式

     public   class  Singleton {
    private static Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

为了解决饿汉式的延迟加载问题,可以使用懒汉式实现,只有在需要使用的时候才实例化,能拖则托。
但是不能保证线程安全。

延迟加载:这种方式单实例  singleton  第一次被引用的时候初始化。
非线程安全:在多线程情况下,如果 singleton 还没有被创建,此时有可能多个线程同时进入 getInstance() 方法中,这时if 判断时 singleton 在都为空,则可能会创建多个实例,与单实例的要求不符,因此不是线程安全的。

    3.懒汉式改进版

     public   class  Singleton {
    private static Singleton instance;
    private Singleton(){}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

为了使得懒汉式变成线程安全的,可以使用内置锁来保证 线程安全。
但是这样却引入了并发性能问题。

延迟加载:这种方式单实例  singleton  第一次被引用的时候创建。
线程安全: 使用 synchronized  给  getInstance() 加锁,这样一次只能有一个线程进入 getInstance() 方法中,也就能满足线程安全了。
并发访问性能: 单实例只会创建一次,所以 getInstance() 中的 if  判断只有第一次请求的时候为true,非第一次请求都会直接返回单实例。 synchronized  给  getInstance() 整个方法加锁 ,方法内 所有的操作都会同步进行的,但是除了第一次创建单实例情况外,根本不需要同步操作,因此如果这个单实例访问频繁,会因为使用同步而影响使用性能。

     4.双重检测锁
    
     public   class  Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
 }

为了解决  懒汉式改进版  中 存在的性能问题,我们使用同步代码块缩小锁的范围,以提高并发量。
两次检测 singleton 是否为空,并使用锁同步实例化代码,因此得名双重检测锁。
但是,这种写法还是 可能 会出现可见性问题。

延迟加载:这种方式单实例  singleton  第一次被引用的时候创建。
线程安全: 使用 synchronized  给创建单实例的代码枷锁,形成同步代码块,保证只创建一次 。
并发访问性能: 只有第一次请求单实例时会进入同步代码块创建单实例,除此之外的其他请求不会进入到同步代码块中, getInstance() 在除第一次访问外相当于没有加锁,也不会造成性能问题。
内存可见性: JVM内存模型有两个重要的概念,叫做指令重排序和内存可见性 , getSingleton() 方法可能会出现这种情况,有多个线程进入了该方法,有一个线程获得了锁进行单实例创建,其他线程直接返回,但是返回的对象却未正常实例化,造成使用时出错。

    5.双重检测锁改进版

     public   class  Singleton {
    private static volatile Singleton singleton;
    private Singleton() {}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

为了解决 双重检测锁中出现的问题,需要使用  volatile   声明 singleton ,以保证单实例创建成功。
但是,这种方法不是通用的。

延迟加载:这种方式单实例  singleton  第一次被引用的时候创建。
线程安全: 使用 synchronized  给创建单实例的代码枷锁,形成同步代码块,保证只创建一次 。
并发访问性能: 只有第一次请求单实例时会进入同步代码块创建单实例,除此之外的其他请求不会进入到同步代码块中, getInstance() 在除第一次访问外相当于没有加锁,也不会造成性能问题。
可见性: 使用 volatile   声明 singleton , volatile 可以保证内存可见性并告诉编译器不进行指令重排序,当 有多个线程进入了 getSingleton() 方法,有一个线程获得了锁进行单实例创建,其他线程直接返回,这时只要单实例完成创建,其他线程就可以立即获得该实例,并且编译器不会进行指令重排,程序会按我们写的代码顺序执行。
通用性: volatile  在 Java 1.5中才发挥上述作用,因此该方法只能在 Java 1.5及 以上才可使用。

6.静态内部类式

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton() {}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}  

延迟加载: SingletonHolder 为静态内部类, Singleton  初始化时不会初始化 SingletonHolder ,只有 通过 显示调用 getInstance() 方法时,才会初始化 SingletonHolder 类,从而实例化单实例,满足延迟加载 。
线程安全:单实例在类加载过程中创建,JVM 保证线程安全 。
并发访问性能: 没有加锁,不会造成并发性能问题。
可见性: 安全,没有先判断再创建的模式 。
通用性: 通用,没有使用 volatile 。

    7.枚举实现
    
     public   enum  Singleton {
    INSTANCE;
    private Singleton() {}
  }

实际工作使用很少。

延迟加载: 满足延迟加载 。
线程安全: 创建枚举默认就是线程安全的。
并发访问性能: 没有加锁,不会造成并发性能问题。
可见性: 安全,没有先判断再创建的模式 。
通用性:1.5之前不可用 。
序列化问题: 无。

    8. 序列化安全

     public   class  Singleton {
    private static volatile Singleton singleton;
    private Singleton() {}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
    private Object readResolve() {
        return singleton;
    }
}

一旦单例实现了序列化接口,那么它可能就不是序列化安全的了,存了枚举实现外,其他方式都存在序列化问题,只要在 Singleton  类中定义 readResolve () 就可以解决该问题。

总结
 
实现单例的方法很多,个人推荐静态内部类的方式,功能完备,使用简单,易于理解。




深入探讨Java中的单例模式及多线程问题 本文深入探讨了Java编程中的单例模式,特别是在多线程环境下如何保证单例模式的正确实现。文章详细解释了通过同步方法解决多线程问题的原理,提出了几种不同的实现策略,并讨论了每种策略的优缺点和适用场景。 阅读详情

相关推荐

第零章 序 Chisel教程汇总

笔者目前西安交通大学微电子硕士在读,研究方向为数字集成电路设计与体系结构。鉴于目前RISC-V的火热程度,笔者参与了课题组的RISC-V项目,并了解、学习了颇受关注的新型硬件构建语言——Chisel,当前参与的神经网络加速器设计便是使用Chisel开发的。这是一门敏捷开发语言,据称要比传统的Verilog语言快很多。在亲身使用过后,笔者发现确实快了不少。这主要得益于Scala作为高级语言的简洁风格...

qq_34291505的博客 7万+

【单例深思】静态内部类实现详解

静态内部类实现是我个人比较推荐的,其实现如下: public class Singleton {     private static class SingletonHolder {         private static final Singleton INSTANCE = new Singleton();     }     private Singleton()

InkGenius 2015

晶圆测试厂wafer map管理建议

按照Recipe设定bin定义 应有版本管理概念,一般使用最新版本做为活动版本即可 Bin明细中应包含 BinID、BinCode、BinName、BinType、BinColor、Description BinID可使用数字类型 BinCode可参照实际机台的Bin,用于匹配 有些公司也将BinID、BinCode理解为SBin和HBin 即 Software Bin & Hardware Bin 一般也将BinID对应到客户的Bin BinType

凯神做开发 1万+

单例模式全解

前言 本文会把我所掌握的所有单例模式都写下 说实话 写法一大堆 网上一查一大把 我总结一下 同时写一下自己的理解和各种单例模式的关系,也算是一个笔记 分类 单例模式写法千千万 总共分为四大类: 懒汉式 饿汉式 注册式 ThreadLocal 1.懒汉式 ...

qq_43091847的博客 166

机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾

f作者: 寒小阳 &&龙心尘 时间:2015年10月。 出处: 声明:版权所有,转载请注明出处,谢谢。手把手机器学习之逻辑回归应用——Kaggle泰坦尼克之灾1.引言先说一句,年末双十一什么的一来,真是非(mang)常(cheng)欢(gou)乐(le)!然后push自己抽出时间来写这篇blog的原因也非常简单: 写完前两篇逻辑回归的介绍和各个角度理解之后,小伙伴们纷纷表示『好像很高级的样纸,

寒小阳 43万+

使用AI编写测试用例——详细教程

现阶段AI还不能完全替代人工测试用例编写,但如果把AI当做一个提高效率的工具,它将会是一个很强大的辅助。

公众号|软件测试老吴 3万+

【单例深思】单例与序列化

在前面的文章中提到,序列化会破坏单例模式,下面用静态内部类的实现方式,说明序列化对单例的影响: public class Singleton implements Serializable{     private static class SingletonHolder {         private static final Singleton INSTANCE = ne

InkGenius 1397

【SigmaStudio】自定义算法组件之XML编写规范(一)

SigmaStudio生成自定义算法组件时,需要XML和DLB文件,本文主要记录XML文件的编码规范

liang_song的博客 1139

单例模式全解析(吐血整理)

一.介绍单例模式 单例模式分为两种:懒汉式(延迟加载)和饿汉式(立即加载),单例模式固然好,但是使用不当也会出现线程安全问题。后面会解释。 二、手写单例模式 饿汉式: class Student{ //构造函数私有 private Student(){}; //成员静态变量初始化本身 private static Student stu=new Student(); //提供公共静态方法...

weixin_41306220的博客 447

提交 ieee 手稿出现:Do not include the Reviewer PDF with my submission 怎么办

IEEE投稿Reviewer PDF选项说明 投稿时出现的"Do not include the Reviewer PDF with my submission"选项控制是否附带评审专用PDF文件。Reviewer PDF是系统自动生成包含所有投稿材料的完整PDF,用于同行评审。建议保持默认不勾选状态,除非确认编辑部不需要该文件,否则可能影响审稿流程。勾选表示不附带此PDF,不勾选则会正常生成并提交该评审文件。

ZhangJiqun&191cm&85kg 2180

Apache Kylin 命令注入漏洞复现(CVE-2020-1956)

Apache Kylin 中的静态 API 存在安全漏洞,可以将os命令与用户输入字符串连接起来,攻击者可以在Kylin没有任何保护或验证的情况下执行任何os命令。

0xSec 1558

springboot 单例_如何实现一个单例及优化

前言社长,一个爱学习,爱分享的程序猿,始终相信,付出总会有回报的。知识改变命运,学习成就未来。爱拼才会赢!程序猿学社的GitHub,已整理成相关技术专刊,欢迎Star:。https://github.com/ITfqyd/cxyxs社长,4年api搬运工程师,之前做的都是一些框架的搬运工作,做的时间越长,越发感觉自己技术越菜,有同感的社友,可以在下方留言。现侧重于java底层学习和算法结构学习,希...

weixin_39805998的博客 2641

QT上位机开发(掌握一点c++基础)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 c++是c语言的补充和扩展,本身的语法构成也是在一直迭代中。相信很多同学上大学读书的时候,或多或少对c语言有所了解,对它的变量、指针、函数也应该不陌生。既然大家都有c语言基础的话,那么在这方面稍微拓展一下的话,就可以学会c++了。当然c++本身的内容很多,很多方面还很琐碎,但我们学习的时候还是应该把精力放在那些经常使用到的语法上面。

嵌入式-老费,一个分享专业嵌入式知识的blog 1131

【单例深思】饿汉式

1、抛出问题 为什么饿汉式单例是线程安全的? 为什么饿汉式单例没有延迟加载(Lazy Loading)? 2、JVM类加载机制 饿汉式单例的实现: public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {} public static Singleton getInstance() {

何武昭的专栏 268

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【单例深思】饿汉式与类加载

我们知道饿汉式的实现是线程安全的,没有延迟加载(Lazy Loading),下面我们深入研究下为什么。 饿汉式的实现如下: public class Singleton {     private static Singleton singleton = new Singleton();     private Singleton() {}     public st

InkGenius 4574

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Design pattern ——singleton pattern(单例总结深思)

Talk is cheapShowmethecode 个人学习笔记--仅供参考 单例模式可以保证内存里只有一个实例,减少了内存开销;可以避免对资源的多重占用。 单例模式看起来非常简单,实现起来其实也非常简单。 总结一下, 前几章主要讲了 饿汉式: 1,经典饿汉式 2静态代码块饿汉式 优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。 缺点:类加载的时候就...

xuedengyong的博客 155

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【java 基础】枚举深思之反编译枚举类,验证枚举实现单例是线程安全的

1、

李光 未来科技 445

《面试宝典》二 如何实现一个单例及优化

前言: 社长,4年api搬运工程师,之前做的都是一些框架的搬运工作,做的时间越长,越发感觉自己技术越菜,有同感的社友,可以在下方留言。现侧重于java底层学习和算法结构学习,希望自己能改变这种现状。 为什么大厂面试,更侧重于java原理底层的提问,因为通过底层的提问,他能看出一个人的学习能力,看看这个人的可培养潜力。随着springboot的流行,大部分的开发,起步就是springboot。也不...

程序猿学社的博客 5142

枚举单例 最安全的单例,可以有效防止反射,序列化

  单例的枚举实现在《Effective Java》中有提到,因为其功能完整、使用简洁、无偿地提供了序列化机制、在面对复杂的序列化或者反射攻击时仍然可以绝对防止多次实例化等优点,单元素的枚举类型被作者认为是实现Singleton的最佳方法。 其实现非常简单,如下: public enum Singleton {     INSTANCE;     private Singleton()...

qq_39843374的博客 2232

Spring单例Bean线程安全吗?90%的面试者都答错了!

面试题:Spring中的单例Bean线程安全吗?Spring中的单例Bean是容器级别的单例,即容器中只存在一个Bean实例。但这并不意味着它本身是线程安全的。线程安全与否取决于Bean是否是无状态的。对于无状态的Bean(例如只执行查询、无共享成员变量),是线程安全的;但如果Bean中存在可变的成员变量,且被多个线程共享访问,则需要开发者自己保证线程安全,比如使用同步机制、线程安全的集合、ThreadLocal 或者更改作用域为 prototype。

Java_fenxiang的博客 666

【单例深思】双重检测锁与Java内存模型

双重检测锁 使用粒度较小的锁(缩小锁的范围)解决了 懒汉式改进版 中存在的性能问题,以提高并发量。 双重检测锁实现如下: public class Singleton {                        // 1     private static Singleton singleton;         // 2     private S

InkGenius 1054
上一篇: 如何使用Spring FactoryBean?
下一篇: 【单例深思】饿汉式与类加载
TaiSung
博客等级 码龄15年 49粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值