美文网首页
设计模式学习专栏二--------单例模式

设计模式学习专栏二--------单例模式

作者: 你的头发真的好长 | 来源:发表于2019-03-10 23:39 被阅读0次

单例模式


单例模式:确保一个类最多只有一个实例,并提供一个全局访问点

有些对象我们只需要一个:线程池、缓存、硬件设备等
如果多个实例会有造成冲突、结果的不一致性等问题

单例模式的类图:

image

由类图转化的代码

#Singleton.java
public class Singleton {
   private static Singleton uniqeInstance=null;
   //私有的构造方法,杜绝了在外界通过new来实例化对象
   private Singleton(){
      
   };
   //在类方法中,专门用来构造Singleton对象。并将该单例对象暴露给外界
   public static Singleton getInstance()
   {
      if(uniqeInstance==null)
      {
         uniqeInstance=new Singleton();
      }
      return uniqeInstance;
   }
}

存在的问题: 在多线程的情况下,如果多个线程同时调用getInstance()方法,则有可能会创建多个实例对象

多线程下可能创建多个实例对象的解决方案

同步(synchronized)getInstance方法

private static Singleton uniqeInstance = null;
public synchronized static Singleton getInstance()
{
   if(uniqeInstance==null)
   {
      uniqeInstance=new Singleton();
   }
   return uniqeInstance;
}

缺点: 每一次调用getInstance() 都会使用锁机制,会非常消耗资源。

“急切”创建实例(饿汉式)

静态成员变量不再为null,而是一开始就为它赋值一个实例

在这种情况下,类一被加载,静态成员变量就被初始化了。 如果程序中的单例对象全都采用这种方法,但某些单例对象从来没被使用过, 那么就会造成内存的浪费。

public class Singleton {
   
   private static Singleton uniqeInstance=new Singleton();
   //私有的构造方法,杜绝了在外界通过new来实例化对象
   private Singleton(){
      
   };
   //在类方法中,专门用来构造Singleton对象
   public synchronized static Singleton getInstance()
   {
      return uniqeInstance;
   }

}

双重检查加锁(延迟加载)

public volatile static ChocolateFactory uniqueInstance = null;
public static ChocolateFactory getInstance() {
   if (uniqueInstance == null) {    //第一重检测
      synchronized (ChocolateFactory.class) {
         if (uniqueInstance == null) {      //第二重检测
            uniqueInstance = new ChocolateFactory();
         }
      }
   }
   return uniqueInstance;
}
  1. 如果第一次实例化时,有多个线程同时通过第一重检测,第二重检测保证了只能有一个线程实例化成功.其他竞争失败的线程直接返回 已创建的实例
  2. 此后所有的实例化经过第一重检测就直接返回
  3. volatile 存在的意义 (见下, 详细可参考并发编程与艺术)
image
  • 上诉代码是一个错误的方案。在线程执行到第4行时,代码读到instance不为null时,instance引用的对象有可能还没有完成初始化

  • 问题的根源

    • 代码的第七行 instance = new Instance(); 创建了一个对象,这一行代码可以分解为如下3行伪代码

      • memory = allocate(); //1. 分配对象的内存空间
      • initInstance(memory) //2. 初始化对象
      • instance = memory ; //3. 设置instance指向刚分配的内存地址
    • 实际上,上面3行代码的2和3有可能发生重排序。 那么在多线程的情况下就有可能 访问到未初始化的对象

    • image
    • 解决方案,使用volatile修饰成员变量instance。第2/3步将会被禁止重排序!

相关文章

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

  • 设计模式学习专栏二--------单例模式

    单例模式 单例模式:确保一个类最多只有一个实例,并提供一个全局访问点 有些对象我们只需要一个:线程池、缓存、硬件设...

  • iOS-单例模式

    swift的单例设计模式 OC的单例设计模式 新学习一种单例思想

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • 设计模式系列教程之单例模式-原理介绍

    设计模式系列教程之单例模式-原理介绍 一:单例模式(Singleton)学习步骤 经典的单例模式原理: 本文出处:...

  • 【Java】设计模式 —— 深入浅出单例模式

    学习笔记 参考:深入浅出单实例SINGLETON设计模式单例模式【Java】设计模式:深入理解单例模式 场景:一般...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • JAVA中各种单例模式的实现与分析

    单例模式是学习设计模式过程中最基本的一个设计模式,基本上一开始学习就会学到单例模式,实际上在java中实现单例模式...

网友评论

      本文标题:设计模式学习专栏二--------单例模式

      本文链接:https://www.haomeiwen.com/subject/urympqtx.html