单例的目的是为了保证运行时Singleton类只有唯一的一个实例,用于一些较大开销的操作。

饿汉式(没有线程安全问题):

由于使用static关键字进行了修饰,只能获取到一个对象,从而达到了单例,并且在Singleton类初始化的时候就创建了对象,加载到了内存。

问题:在没有使用这个对象的情况下就加载到内存是一种很大的浪费。

针对这种情况,有一种新的思想提出——延迟加载,也就是所谓的懒汉式。

懒汉式(存在线程安全问题):

这种方法在调用Singleton.getInstance()时才会创建对象,起到了延迟加载的作用。

问题:这样的写法在多个线程同时运行时,很有可能会产生多个实例对象,导致线程安全问题。

使用同步的方法解决这个问题,加上synchronized关键字,代码如下:

  使用同步的代价是会在一定程度上降低程序的并发度,并且锁定整个方法很消耗资源,原本采用延迟加载是为了节省资源,

所以,降低锁的细粒度,代码如下:

  但是这样的写法线程还是不安全,因为两个线程可以同时进入if语句,线程A实例化对象返回之后,线程B不用经过判断

能再实例化对象,并且返回另一个对象。为了解决这个问题,引入了臭名昭著的双重锁机制:

上面的代码看似解决了线程安全问题,也起到了延迟加载的作用,但是双重锁机制是没有办法工作的,有一篇文章解释的非常

深刻:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

在参考了一些资料,我认为双重锁机制之所以不能正常运行是因为,在new对象的时候,是有三个步骤的:分配内存空间,

初始化对象,然后将内存地址赋值给变量;在这么三个步骤中,极有可能会在操作上进行重排序,在重排序的情况下,还没有初始化

对象,先将内存地址赋值给了变量(这种情况是可能存在的),当线程B进入时,发现变量不为null,就会直接返回这个实例,然而此时

可能拿到的是还没有初始化完成的对象。所以双重锁机制是不提倡使用的。

在http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl文章中有提出,在新的内存模型下,实例字段使用volatile可以解

决双重锁检查的问题,因为在新的内存模型下,volatile禁止了一些重排序,但是,同时,使用volatile的性能开销也有所上升。

所以又提出一种新的模式——Initialization on Demand Holder. 这种方法使用内部类来做到延迟加载对象,在初始化这个内部类的时候,

JLS(Java Language Sepcification)会保证这个类的线程安全。代码如下:

最新文章

  1. NYOJ-858下三角矩阵
  2. 初学My Batis之入门
  3. 头像上传,拖拽,裁切 (非HTML5)版本
  4. Community Value再理解
  5. T3 任职定级面试准备
  6. 《sed的流艺术之二》-linux命令五分钟系列之二十二
  7. 合理的使用size_t可以提高程序的可移植性和代码的可读性,让你的程序更高效。
  8. URL匹配与req参数解析
  9. 一个web应用的诞生(13)--冲向云端
  10. 基于PLC1850平台的ARP包请求与响应
  11. VS2017 处理 Rdlc , microsoft report viewer 轻量级报表处理(WPF CS客户端版本)
  12. LodopJS代码模版的加载和赋值
  13. 完整性约束&外键变种三种关系&数据的增删改
  14. InvokeRepeating重复定时器
  15. cas 服务端相关配置
  16. Codeforces 681C. Heap Operations 优先队列
  17. multiple definition of 问题解决方法
  18. IE8中伪元素动态作用样式不重绘bug记录
  19. IAR使用notice
  20. JSON.parse() 方法解析一个JSON字符串

热门文章

  1. 三、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的08-12示例
  2. Spark—RDD编程常用转换算子代码实例
  3. Spring 学习笔记(2) Spring Bean
  4. 静态Web服务器(py版)
  5. 前端构建第1篇之---引入elementUI
  6. Couchdb 垂直权限绕过漏洞(CVE-2017-12635)
  7. Netty入门(一):ByteBuf
  8. QT: 如何移动和缩放一个无边框窗口
  9. idea创建普通Web项目lib目录无法输出,tomcat不报错问题
  10. 如何开启MySQL远程连接