单例模式,顾名思义,就是在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. Hystrix原理与实战(转)

    背景 分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务.如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服 ...

  2. Spring AOP(通知、连接点、切点、切面)

    一.AOP术语 通知(Advice)  切面的工作被称为通知.通知定义了切面是什么以及何时使用.除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题.5种通知类型: 前置通知(Before): ...

  3. lintcode 394. Coins in a Line 、leetcode 292. Nim Game 、lintcode 395. Coins in a Line II

    变型:如果是最后拿走所有石子那个人输,则f[0] = true 394. Coins in a Line dp[n]表示n个石子,先手的人,是必胜还是必输.拿1个石子,2个石子之后都是必胜,则当前必败 ...

  4. sqllite connectionstring setting

    https://www.connectionstrings.com/sqlite/ SQLite.NET Basic Data Source=c:\mydb.db;Version=3; Version ...

  5. MFC加载osg模型

    创建MFC单文档项目, OSGObject.h #pragma once #include <osgViewer\Viewer> #include <osgDB\ReadFile&g ...

  6. 转 Java连接Oracle数据库的简单示例

    https://www.cnblogs.com/joyny/p/11176643.html https://community.oracle.com/thread/4096458 import jav ...

  7. ios开发将截图保存到相册

    - (void)loadImageFinished:(UIImage *)image { UIImageWriteToSavedPhotosAlbum(image, self, @selector(i ...

  8. 今天被这个BDE错误搞了半天,不过终于好了,分享一下

    今天正编译程序时,突然就报了这个错误出来,重启电脑都没用,多亏网上高手指教,先把解决方案列于下,供受此累得朋友查阅,自己也留底供查找:"Shared memory conflict ($21 ...

  9. 推荐两本CCF教材

    希望学习电脑程序设计的同学,可以购买如下两本教材,先学习入门篇,再学习基础篇.淘宝.当当.京东均有售.建议选择比较靠谱的网店,避免买到盗版书.

  10. request.GET、request.POST、request.body(持续更新)

    1.request.GET: print(request.GET) # <QueryDict: {'page' : ['5'], 'id__gt' : ['4']}> print(requ ...