单例模式的七种写法

第一种(懒汉,线程不安全):

这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。

第二种(懒汉,线程安全):

这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

第三种(饿汉):

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。

第四种( 饿 汉,变种):

表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。

第五种(静态内部类):

这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。

第六种(枚举):

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

第七种(双重校验锁):

在JDK1.5之后,双重检查锁定才能够正常达到单例效果。

有两个问题需要注意:

1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

对第一个问题修复的办法是:

对第二个问题修复的办法是:

对我来说,我比较喜欢第三种和第五种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第三种方式,只有在要明确实现lazy loading效果时才会使用第五种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全的,而且我永远不会使用第一种和第二种方式,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。

========================================================================

我很高兴有这样的读者,一起共勉。

Original: https://www.cnblogs.com/goody9807/p/7395167.html
Author: PointNet
Title: 单例模式的七种写法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551818/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Centos7: 防火墙相关

    防火墙 开放端口 firewall-cmd –zone=public –add-port=5672/tcp –permanent # 开&#x6…

    技术杂谈 2023年7月24日
    057
  • 树状数组二分

    #include//树状数组二分 using namespace std; int q,b,s,…

    技术杂谈 2023年6月21日
    0107
  • 每天一个 HTTP 状态码 100

    100 Continue 指示客户端应该继续当前请求;如果请求已经完成… 100 Continue 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分;指示客户…

    技术杂谈 2023年7月11日
    067
  • Consul注册中心删除某个服务

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    技术杂谈 2023年5月31日
    0106
  • 搭建简单JavaWeb项目

    参考:(17条消息) 手把手搭建一个完整的javaweb项目(适合新手)_心歌技术的博客-CSDN博客_javaweb项目完整案例 补充项目结构的细节,进行了一点修改,修改为学生信…

    技术杂谈 2023年6月21日
    0101
  • ThreeJS简介介绍

    Three.js的学习问题 Three.js的入门是相对简单的,但是当我们真的去学的时候,会发现一个很尴尬的问题:相关的学习资料很少。通常这种流行的库都有很完善的文档,很多时候跟着…

    技术杂谈 2023年5月31日
    0120
  • Idea中@Autowired 黄色波浪线问题以及注入类显示红色波浪线问题解决

    解决办法: 点开路径:File—>Settings—>Editor—>Inspections—>Spring…

    技术杂谈 2023年6月1日
    0106
  • GO 锁

    执行1:Done ~ 59534 执行2:Done ~ 50243 可以看出每次执行结果不一,原因:共有变量x,没加锁,导致可能同时获取到加1,导致只加了1次 执行: 111.77…

    技术杂谈 2023年5月31日
    079
  • 技术解码 | RSFEC原理分析

    今天向大家介绍下RSFEC的原理,它通过生成冗余数据来恢复丢失的信息,首先介绍下背景,之后重点介绍RSFEC如何计算冗余和恢复数据的,分为异或方式和矩阵方式,异或方式可以认为是矩阵…

    技术杂谈 2023年5月31日
    088
  • SSM配置文件的连接

    使用ssm框架配置数据库连接时的问题 如果MySQL数据库版本是8.0.11, url配置成了MySql5.0以上版本需要的驱动类名(com.mysql. cj.jdbc.Driv…

    技术杂谈 2023年6月21日
    094
  • SQL 基础

    在平时的工作中,大家可能是 ORM 战士。但是 ORM 之下,还是原生的 SQL。这是整理 SQL 基础时的一些记录。 数据定义语言,用来定义数据库对象,包括数据库、数据表和列。 …

    技术杂谈 2023年7月11日
    062
  • 用户成长体系-规划

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/shoshana-kong/p/16498628.htm…

    技术杂谈 2023年6月1日
    0103
  • Word书签替换,加盖电子印章及转换PDF(Java实用版)

    一、前言 在项目中有需要对word进行操作的,可以看看哈,本次使用比较强大的spire组件来对word进行操作,免费版支持三页哦,对于不止三页的word文件,可以购买收费版,官网:…

    技术杂谈 2023年6月21日
    0113
  • 源码级别的广播与监听实现

    原创:微信公众号 【阿Q说代码】,欢迎分享,转载请保留出处。 近期疫情形势严峻,情形不容乐观,周末也不敢出去浪了,躲在家里”葛优躺”。闲来无事,又翻了遍 S…

    技术杂谈 2023年7月11日
    079
  • 安装Harbor之http版本

    一、安装Harbor Harbor简介 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展…

    技术杂谈 2023年5月31日
    082
  • jmeter+Prometheus+Grafana集成

    jmeter+Prometheus+Grafana集成在JMeter插件库中,有一些后端监听器可供Kafka、ElasticSearch和Azure使用。默认情况下,Jmeter支…

    技术杂谈 2023年5月30日
    085
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球