单例模式,顾名思义,就是在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. uboot下如何使用fatls工具?

    答: 如列出第一个sd卡第一个分区中的文件: fatls mmc 0:1 /

  2. pl/sql用for in和for select into循环遍历表

    create or replace procedure test_procedure_job asv1 varchar2(50);v2 varchar2(50);v3 varchar2(50);beg ...

  3. eclipse默认指向WebContent目录修改为webRoot 设置说明【也适用于Eclipse启动MyEclipse项目】

    转: eclipse默认指向WebContent目录修改为webRoot 设置说明 2014-07-02 17:42:58 落叶上的秋 阅读数 8618更多 分类专栏: Eclipse 问题   l  ...

  4. 【DataBase】H2 DateBase与项目集成

    本例介绍H2与web项目的集成 项目启动H2数据库 1.新建Maven Web项目,参考:[Maven]Eclipse 使用Maven创建Java Web项目 2.引入h2的jar包依赖 <de ...

  5. Elasticsearch技术解析与实战 PDF (内含目录)

    Elasticsearch技术解析与实战                                  介绍: Elasticsearch是一个强[0大0]的搜索引擎,提供了近实时的索引.搜索.分 ...

  6. SQL Server判断对象是否存在

    1 判断数据库是否存在 if exists (select * from sys.databases where name = ’数据库名’) drop database [数据库名] if exis ...

  7. 【VxWorks工程】基于opencv创建读取摄像头数据的工程error

    工程编译遇到的问题: Cannot step: Signal : Segmentation violation bytes (0x20 aligned) in partition 0x2023d930 ...

  8. 【linux学习笔记一】目录处理命令

    一 建立目录:mkdir make directories //创建一个name的目录 mkdir name //-p 递归创建 //在没有目录a也没有目录b的情况下 直接创建 mkdir -p a/ ...

  9. JS扩展Array.prototype引发的问题及解决方法

    遇到的问题 一上班收到个bug,写的表单联动插件在ie里面会出现js源码,当时有点意外,从没出现过这问题. 问题的原由 为什么会出现一个function呢?其它调用的插件的页面为什么没有这问题? 控制 ...

  10. web端调起Windows系统应用程序(exe执行文件),全面兼容所有浏览器

    1. 首先,你要有一个exe可执行文件2. 创建注册表创建注册表有两种方式(以“MyApp.exe”为例): 方式一:可视化编辑Win+R 打开运行,输入 regedit 并回车,进入注册表编辑器新建 ...