单例模式的DCL是一种比较好的单例实现方式,面试中被问及的频率非常高,考察的方式也多种多样。这里简单整理了一下,这里面的每一个点最好都能够做到烂熟于心:

 1 public class Test {
2 private volatile static Test instance;
3
4 private Test() {
5
6 }
7
8 public static Test getInstance() {
9 if (instance == null) {
10 synchronized (Test.class) {
11 if (instance == null) {
12 instance = new Test();
13 }
14 }
15 }
16 return instance;
17 }
18 }

这里有5个要点需要注意:

(1)第一个注意点:使用私有的构造函数,确保正常情况下该类不能被外部初始化(非正常情况比如通过反射初始化,一般使用反射之后单例模式也就失去效果了)。

(2)第二个注意点:getInstance方法中第一个判空条件,逻辑上是可以去除的,去除之后并不影响单例的正确性,但是去除之后效率低。因为去掉之后,不管instance是否已经初始化,都会进行synchronized操作,而synchronized是一个重操作消耗性能。加上之后,如果已经初始化直接返回结果,不会进行synchronized操作。

(3)第三个注意点:加上synchronized是为了防止多个线程同时调用getInstance方法时,各初始化instance一遍的并发问题。

(4)第四个注意点:getInstance方法中的第二个判空条件是不可以去除,如果去除了,并且刚好有两个线程a和b都通过了第一个判空条件。此时假设a先获得锁,进入synchronized的代码块,初始化instance,a释放锁。接着b获得锁,进入synchronized的代码块,也直接初始化instance,instance被初始化多遍不符合单例模式的要求~。加上第二个判空条件之后,b获得锁进入synchronized的代码块,此时instance不为空,不执行初始化操作。

(5)第五个注意点:instance的声明有一个voliate关键字,如果不用该关键字,有可能会出现异常。因为instance = new Test();并不是一个原子操作,会被编译成三条指令,如下所示。
          1)给Test的实例分配内存

2)初始化Test的构造器

3)将instance对象指向分配的内存空间(注意,此时instance就不为空)

然后咧,java会指令重排序,JVM根据处理器的特性,充分利用多级缓存,多核等进行适当的指令重排序,使程序在保证业务运行的同时,充分利用CPU的执行特点,最大的发挥机器的性能!简单来说就是jvm执行上面三条指令的时候,不一定是1-2-3这样执行,有可能是1-3-2这样执行。如果jvm是按照1-3-2来执行的话,当1-3执行完2还没执行的时候,如果另外一个线程调用getInstance(),因为3执行了此时instance不为空,直接返回instance。问题是2还没执行,此时instance相当于什么都没有,肯定是有问题的。然后咧,voliate有一个特性就是禁止指令重排序,上面的三条指令是按照1-2-3执行的,这样就没有问题了。

参考:https://blog.csdn.net/hnd978142833/article/details/81633730

单例模式的DCL方式,您不可不知道的知识点的更多相关文章

  1. JavaScript 优雅的实现方式包含你可能不知道的知识点

    有些东西很好用,但是你未必知道:有些东西你可能用过,但是你未必知道原理. 实现一个目的有多种途径,俗话说,条条大路通罗马.很多内容来自平时的一些收集以及过往博客文章底下的精彩评论,收集整理拓展一波,发 ...

  2. CSS3 Transitions 你可能不知道的知识点

    如何临时让transition失效 我们给一个element设置了transition效果,但某些特殊情况,我们希望让transition临时失效.我们第一反应就是先移除transition设置,等其 ...

  3. Android Context完全解析,你所不知道的Context的各种细节

    Context相信所有的Android开发人员基本上每天都在接触,因为它太常见了.但是这并不代表Context没有什么东西好讲的,实际上Context有太多小的细节并不被大家所关注,那么今天我们就来学 ...

  4. 你所不知道的setTimeout

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...

  5. 你可能不知道的陷阱, IEnumerable接口

    1.  IEnumerable 与  IEnumerator IEnumerable枚举器接口的重要性,说一万句话都不过分.几乎所有集合都实现了这个接口,Linq的核心也依赖于这个万能的接口.C语言的 ...

  6. 你所不知道的15个Axure使用技巧

    你有用原型开发工具吗?如果有,那你用的是Axure还是别的? 从以前就喜欢使用Axure,主要是觉得它能清楚的表达设计的思路,还有交互的真实再现,能让看的人一目了然,昨天看了这篇博文,便更加确定Axu ...

  7. 你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧

    目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程. ...

  8. 关于Promise:你可能不知道的6件事

    FROM ME : 文章介绍了6个Promise的知识点: 1.then() 返回一个 forked Promise(分叉的 Promise):返回的有两种情况: 2.回调函数应该传递结果:在 pro ...

  9. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

随机推荐

  1. 编译安装路由器用的Privoxy 3.0.28(华硕RT-AC88U,原版梅林384.15)

    编译安装路由器用的Privoxy 3.0.28(华硕RT-AC88U,原版梅林384.15) Privoxy有什么特殊之处? 支持和SOCKS/HTTP代理的级联.这个功能轻松将SOCKS转为HTTP ...

  2. centOS 6.8下使用Gparted进行分区扩容

    centOS 6.8下使用Gparted进行分区扩容 ​ 机器环境:windows上运行的VMware虚拟机,系统为centOS 6.8. ​ 由于前期分区分配空间过小,无法满足后续的数据存储预期,所 ...

  3. Java程序员的两项通用能力

    工作这几年来,经历了很多.从小白到中级(手机里有一款叫中国象棋的游戏,里面给对弈中电脑水平分为小白.菜鸟.新手.入门.初级.中级.高级.大师.特级大师,编程我暂且按照这样来区分). 学校教给我的是从小 ...

  4. 【Copy攻城狮日志】Node快速重命名文件,告别Potplay字幕困扰问题

    ↑开局一张图,故事全靠编↑ 前言 Copy攻城狮日志的惯例,开局一张图,开始为您讲述一个鲜为人知的故事.故事的开头要从本大狮从盗版网站下载udemy课程的犯罪伊始说起,去年的某月某天,我真正接触到了“ ...

  5. Java岗位面试题分享:jvm+分布式+消息队列+协议(已拿offer)

    个人近期面试情况 今年二月以来,我的面试除了一个用友的,基本其他都被毙了,可以说是非常残酷的.其中有很多自己觉得还面的不错的岗位,比如百度.跟谁学.好未来等公司.说实话,打击比较大. 情况基本上是从三 ...

  6. Docker 入门:镜像

    主要内容: 什么是镜像 下载镜像 pull 设置下载加速源 查看镜像 上传镜像 push 什么是镜像(image) 镜像是一个文件系统,提供了容器运行时需要用到的文件和参数配置.相当于平时在使用某个软 ...

  7. Spring_使用JdbcTemplate和JdbcDaoSupport

    1.JdbcTemplate 简化 JDBC 模板查询 ①每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下.②JdbcTemplate 类被设计成为线程安全的, 所以可以再 ...

  8. SDL初识

    1.SDL是什么? SDL(Security Development Lifecycle)安全开发生命周期.是微软提出的从安全角度指导软件开发的管理模式,在软件开发的生命周期中尽可能地发现安全隐患,降 ...

  9. 利用metasploit复现永恒之蓝

    环境 目标机器:windows 7 ,172.16.136.169 攻击机:安装了Metasploit 的 ubuntu16.04 ,172.16.136.130 (安装Metasploit:在 Ub ...

  10. Spring boot Sample 007之spring-boot-log4j2

    一.环境 1.1.Idea 2020.1 1.2.JDK 1.8 二.目的 spring boot 整合多环境log4j2 三.步骤 3.1.点击File -> New Project -> ...