下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、如何止确地写出单例模式编程 开发技术如何正确地写出单例模式原文出处:伍艸单例模式算是设计模式中最容易理解,也是最容易手写代码的模式了吧。但是其 中的坑却不少,所以也常作为面试题來考。本文主耍对几种单例写法的整理,并 分析其优缺点。很多都是一些老生常谈的问题,但如果你不知道如何创建一个线 程安全的单例,不知道什么是双检锁,那这篇文章可能会帮助到你。懒汉式,线程不安全当被问到要实现一个单例模式时,很多人的第一反应是写出如卜的代码,包括教 科书上也是这样教我们的。public class singleton private static singleton instanee;private sing
2、leton () public static singleton getlnstance() if (instance 二二 null) instanee 二 new singleton();rcturn instancc;这段代码简单明了,而h使用了懒加载模式,但是却存在致命的问题。当有多个 线程并行调用getlnstance0的时候,就会创建多个实例。也就是说在多线程 下不能正常工作。懒汉式,线程安全为了解决上面的问题,最简单的方法是将整个getlnstance()方法设为同步(synchronized)。public static synchronized singleton getln
3、stance() if (instance = null) instance 二 new singleton();return instanee;虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。因为在任何 时候只能有一个线程调用gettnstanceo方法。但是同步操作只需耍在第一次 调用时才被需要,即第一次创建单例实例对象时。这就引岀了双重检验锁。双重检验锁双重检验锁模式(double checked locking pattern),是一种使用同步块加锁 的方法。程序员称其为双重检查锁,因为会有两次检查?instance = null, 次是在同步块外,一次是在同步块内。为什么
4、在同步块内还要再检验一次?因为 可能会有多个线程一起进入同步块外的if,如果在同步块内不进行二次检验的 话就会生成多个实例了。/single checked/double checkedpublic static singleton getsingleton() if (instance 二二 null) synchronized (singleton .class) if (instanee = null) instance = new singleton ();return instance ;这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new singleto
5、n()这句,这并非是一个原子操作,事实上在jvm中这句话大概做了下 面3件事情。1. 给insumce分配内存2. 调用singleton的构造函数來初始化成员变量3. 将instance对象指向分配的内存空间(执行完这步instance就为非null 了) 但是在jvm的即时编译器中存在指令重排序的优化。也就是说上面的第二步和 第三步的顺序是不能保证的,最终的执行顺序可能是1-2-3也可能是1-3-2。 如果是后者,则在3执行完毕、2未执行之前,被线程二抢占了,这时instance 已经是非null 了(但却没有初始化),所以线程二会直接返回instance,然 后使用,然后顺理成章地报错。
6、我们只需要将instance变量声明成volat订e就可以了。public class singleton private volatile static singleton instance; /声明成 volati le private singleton () public static singleton getsingleton() if (instanee 二二 null) synchronized (singleton, class) if (instancc = null) instanee = new singleton();rcturn instancc;i有些人认为使用v
7、obt订e的原因是可见性,也就是可以保证线程在本地不会存 有instance的副本,每次都是去主内存小读取。但其实是不对的。使用 volatile的主要原因是其另一个特性:禁止指令重排序优化。也就是说,在 volatile变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操 作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完1-2-3 之后或者1-3-2之后,不存在执行到1-3然后取到值的情况。从先行发生原 则的角度理解的话,就是对于一个vol at订c变量的写操作都先行发生于后而 对这个变量的读操作(这里的“后面”是时间上的先后顺序)。但是特别注意在java 5以前的版
8、本使用了 vobt订e的双检锁还是有问题的。 其原因是java 5以前的jmm (java内存模型)是存在缺陷的,即吋将变量声 明成volatile也不能完全避免重排序,主要是volatile变量前后的代码仍然 存在重排序问题。这个volatile屏蔽重排序的问题在java 5中才得以修复, 所以在这z后才可以放心使用volatile。相信你不会喜欢这种复杂乂隐含问题的方式,当然我们有更好的实现线程安全的 单例模式的办法。饿汉式 static final field这种方法非常简单,因为单例的实例被声明成static和final变量了,在第 一次加载类到内存屮时就会初始化,所以创建实例本身是线
9、程安全的。public class singleton!类加载吋就初始化private static final singleton instance = new singleton();private singleton() public static singleton getlnstance()return instance;这种写法如果完美的话,就没必要在啰嗦那么多双检锁的问题了。缺点是它不是 一种懒加载模式(lazy initialization),单例会在加载类后一开始就被初始 化,即使客户端没有调用getlnstance ()方法。饿汉式的创建方式在一些场景中 将无法使用:譬如s
10、ingleton实例的创建是依赖参数或者配置文件的,在 getlnstance()之前必须调用某个方法设置参数给它,那样这种单例写法就无法 使用了。静态内部类 static nested class我比较倾向于使用静态内部类的方法,这种方法也是effective java上所推 荐的。public class singleton private static class singletonllolder private static final singleton instance = new singleton();private singleton () publ ic static fi
11、nal singleton getlnstance() return singletonllolder. instance;这种写法仍然使用jvm木身机制保证了线程安全问题;由于singletonholder 是私有的,除了 getlnstance()之外没有办法访问它,因此它是懒汉式的;同 时读取实例的时候不会进行同步,没有性能缺陷;也不依赖jdk版本。枚举enum用枚举写单例实在太简单了!这也是它最大的优点。下面这段代码就是声明枚举 实例的通常做法。public enum easysingletoninstance;我们可以通过easysingleton. instance来访问实例,这比调用getlnstance () 方法简单多了。创建枚举默认就是线程安全的,所以不需要担心double checked locking,而且还能防止反序列化导致重新创建新的对象。但是还是很少看到冇 人这样写,可能是因为不太熟悉吧。总结一般來说,单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举。 上述所说都是线程安全的实现,文章开头给岀的第一种方法不算正确的写法。就我个人而言,一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向丁-使用静态内部类,如果涉及到反序列化创建对象时会 试着使用枚举的方式来实现单例。re
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年甲乙双方关于新建文化传媒公司的股权转让合同
- 二零二五年度住宅装修消防设施合同3篇
- 2025版股票质押业务尽职调查合同范本3篇
- 二零二五年度商业综合体监理合同终止及消防验收协议3篇
- 2024年林业用地树木砍伐与生态补偿合同范本3篇
- 二零二五年度BIM咨询与建筑工程节能改造合同2篇
- 二零二五年度信用卡透支借款合同打印范本3篇
- 土方回填工程合同
- 物业管理水电工服务合同
- 2025年客服部经理年度工作总结范文(2篇)
- GA 1802.2-2022生物安全领域反恐怖防范要求第2部分:病原微生物菌(毒)种保藏中心
- 企业EHS风险管理基础智慧树知到答案章节测试2023年华东理工大学
- 健身俱乐部入场须知
- 井下机电安装安全教育培训试题及答案
- TZJXDC 002-2022 电动摩托车和电动轻便摩托车用阀控式铅酸蓄电池
- GB/T 4744-2013纺织品防水性能的检测和评价静水压法
- GB/T 337.1-2002工业硝酸浓硝酸
- 《解放战争》(共48张PPT)
- 放射工作人员法律法规及防护知识培训考核试题附答案
- 劳动仲裁追加申请申请书(标准版)
- 西方法律思想史 课件
评论
0/150
提交评论