单例模式,顾名思义,就是在Java程序中只有唯一一个实例,这样做的好处是可以在不需要多个实例的对象采用单例模式可以节省内存,否则会造成不必要的内存浪费。单例模式的定义为:保证一个类只有一个实例,自己可以初始化自己,且全局可以访问。该模式在Java中广泛使用,例如连接池,连接池一般只需要一个,就采用这种设计模式。

  单例模式又分为“饿汉”和“懒汉”两种。

  “饿汉”模式:

  “懒汉”模式:在懒汉模式情况下需注意并发情况下获取实例方法的线程安全问题,该问题指的是初始化多个实例,这样就违背了我们的初衷,虽然最后不可达的对象会被JVM回收,但是也存在隐患的问题。如下图,这里使用了synchonized关键字对该方法进行加锁,但是这种方式存在很明显的问题,接着往下看:

  我们使用synchonized是为了避免初始化多个实例,但是这个问题只存在于第一次访问该对象的时候,之后初始化好了 null != instance 了,就不存在这个问题了,但是由于synchonized关键字的存在,导致每次获取实例都会进行线程等待,很大程度上会影响执行的效率,有一种方式叫做双重检查加锁,如:

  

  现进行判断instance引用是否已经指向了内存空间(即判断instance ==null是否成立的条件),没有就对该对象进行加锁,然后在进行判断一次,还没有的话进行初始化,这样只有第一次初始化的时候会进行加锁校验,这就解决问题了吗?答案是并没有,请注意本段中加粗斜体的文字,由于JMM(Java Memory Model Java内存模型)中说了,存在三个特性,原子性,可见性,有序性,关于JMM会在之后自己深入学习的时候单独进行记录,现在不敢误导别人,读者只需先知道存在这个即可,java代码在进行编译的时候,会对代码指令进行重新排序,上述代码中我用红色箭头指向的那一句,并不是一个原子性操作(可理解为一步就能搞定的操作),其指令可以分解为:

  1.new 关键字在堆中为其分配内存空间

  2.在分配好的内存空间中初始化该对象

  3.将instance的引用指向该内存地址

  如果是顺序执行的话,自然没有什么问题,但是如果指令重新排序成为1,3,2这样来进行执行的话,在两个线程并发的情况下可能会导致这种情况:

  t1:发现instance引用未指向内存空间,抢占到锁,分配内存空间,将instance引用指向该空间,此时让出时间片

  t2:发现instance引用已经指向了某一内存空间,不进行初始化,直接引用该对象,但是请注意,此时该对象尚未进行初始化。

  这样就会导致问题产生,如何来解决呢?

  Java给我们提供了volatile关键字,被该关键字修饰的变量会依据“do-before”原则,所有该变量的读操作都会在写操作完成之后,禁止指令的重排序,这样就能保证t2线程拿到的是初始化好的对象了,所以,懒汉模式的最终代码如下:

  

  此外,还有一种使用静态内部类的方法通过饿汉模式中的类加载机制实现延迟加载和保证并发环境下的线程安全,只有在调用getInstance方法的时候才会加载内部类使用类加载机制进行初始化,天生线程安全:

  

  

单例模式详解以及需要注意的地方(Singleton)的更多相关文章

  1. 9种Java单例模式详解(推荐)

    单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象.  懒汉式(线程不安全) 其主要表现在单例类在外 ...

  2. JAVA设计模式(6:单例模式详解)

    单例模式作为一种创建型模式,在日常开发中用处极广,我们先来看一一段代码: // 构造函数 protected Calendar(TimeZone var1, Locale var2) { this.l ...

  3. Java设计模式之单例模式详解

    在Java开发过程中,很多场景下都会碰到或要用到单例模式,在设计模式里也是经常作为指导学习的热门模式之一,相信每位开发同事都用到过.我们总是沿着前辈的足迹去做设定好的思路,往往没去探究为何这么做,所以 ...

  4. Java双重校验单例模式详解

    单例模式双重检测java实现: public class Singleton { private volatile static Singleton instance = null; //#1 pub ...

  5. Java 单例模式详解

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...

  6. C#单例模式详解

    C#要实现单例模式必须要有以下三点: 声明私有静态成员.私有化构造函数.静态函数返回实例. private static GameManager s_GameManager=null; private ...

  7. java单例模式详解

    饿汉法 饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建.代码如下: public class Singleton { private static Singleton = ne ...

  8. 【JAVA单例模式详解】

    设计模式是一种思想,适合于任何一门面向对象的语言.共有23种设计模式. 单例设计模式所解决的问题就是:保证类的对象在内存中唯一. 举例: A.B类都想要操作配置文件信息Config.java,所以在方 ...

  9. Objective-c单例模式详解

    转载自:http://www.jianshu.com/p/85618bcd4fee 单例模式出现以后,关于它的争执就一直存在.在开发项目中,有很多时候我们需要一个全局的对象,而且要保证全局有且仅有一份 ...

随机推荐

  1. SeetaFace2 cmake VS2015编译编译

    cmake Selecting Windows SDK version 10.0.17134.0 to target Windows 10.0.18362. == BUILD_VERSION: v2. ...

  2. IoAllocateMdl,MmProbeAndLockPages的用法

    转载地址:https://blog.csdn.net/wdykanq/article/details/7752909 IoAllocateMdl,MmProbeAndLockPages的用法 第一,M ...

  3. 深入学习c++--容器

    1. 简介 1. 序列式容器: array, vector, deque, list, forward_list --- 数组 或者 指针实现 2. 关联容器: set, map, multiset, ...

  4. k8s记录-dockerfile

    FROM 代表基于哪个镜像 RUN 安装软件使用 MAINTAINER 镜像的创建者 CMD 容器启动时执行的命令,但是一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD EN ...

  5. javaselenium遇到的问题和解决方法(还没试,遇到问题可以先看这里)

    Firefox路径问题 firefox火狐浏览器去完成自动化测试时,代码报了如下错误: Cannot find firefox binary in PATH. mark sure firefox is ...

  6. 01点睛Spring MVC 4.1-搭建环境

    转发:https://www.iteye.com/blog/wiselyman-2213906 1.1 简单示例 通篇使用java config @Controller声明bean是一个控制器 @Re ...

  7. Freemarker讲解

    FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP.它不仅可以用作表现层的实现 ...

  8. 【JS】逻辑处理

    1.计算会员进度 const a = res.data.directCount(当前充值点券) / nextLevelData.map(item => item.direct_number(下一 ...

  9. linux maven环境变量配置

    export MAVEN_HOME=/opt/hjyang/soft/maven export MAVEN_HOME export PATH=$PATH:$MAVEN_HOME/bin

  10. Appium移动自动化测试-----(六)4.运行第一个Appium脚本

    新建maven空白工程 前置条件:安装eclipse或IntelliJ IDEA,及其maven插件,请自行百度 新建的工程如下: 新建目录apps,并将下载的安装包,拷贝到该目录下 打开POM增加依 ...