单例模式,顾名思义,就是在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. GPRS以TCP上传数据到服务器OK,但收不到服务器下发的数据

    GPRS以TCP上传数据到服务器OK,但收不到服务器下发的数据 基站漂移是DTU很常见的连接故障,一个DTU所处的地方可能会有多个基站信号,时间久了,可能会在不同的基站之间切换,它会更新自己的连接,发 ...

  2. ubuntu上的 /dev/loop0 到 /dev/loop18占到100%的处理

    date : 2019-08-13  09:39:09 author: headsen  chen 处理方法:apt autoremove --purge snapd 再次检测:

  3. 在windows上编译chrome浏览器Building Chromium for Windows

    web端用webRTC实现的一对一视频,互动直播和会议.https://github.com/starrtc/android-demo Chromium requires Visual Studio ...

  4. Android输入法遮挡了输入框,使用android:fitsSystemWindows="true"后界面顶部出现白条解决方案

    我的最外层是LinearLayout,自定义CustomLinearLayout继承LinearLayout,重写fitSystemWindows和onApplyWindowInsets两个方法: p ...

  5. openpyxl代码案例

    import datetimefrom random import choicefrom time import timefrom openpyxl import load_workbookfrom ...

  6. weui 导航悬浮固定

    <style> .none{display: none} #toolbar { display: flex; justify-content: center; align-items: c ...

  7. flutter的加载弹框

    代码组件: import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'packa ...

  8. DRBD UpToDate/DUnknown 故障恢复

    故障如下: root@drbd1:~# drbd-overview 0:data/0 StandAlone Primary/Unknown UpToDate/DUnknown /data/mysql ...

  9. 【php】PHP制作QQ微信支付宝三合一收款码

    分析 微信扫这个,支付宝扫那个,不仅要加载多张二维码,还要加css/js让它变的好看,作为一个又懒又不想写这些东西的程序猿来说,这可不行. 那能不能把QQ微信支付宝三合一,只需要扫一个收款码就行呢? ...

  10. LeetCode_217. Contains Duplicate

    217. Contains Duplicate Easy Given an array of integers, find if the array contains any duplicates. ...