`
ymm8505
  • 浏览: 33278 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一次搞定 单例模式

阅读更多
单例模式 大家都不陌生、但是写出一个让人满意的单例 并不是那么容易的。
从另一个角度来分析单例模式 方便大家理解。

单例模式:只能创建出类的一个对象 也是唯一的一个对象。
怎么保障只能创建出一个类对象呢?
  首先想到的是静态 静态对象是属于类的。所以能保证静态对象的唯一。
  其次屏蔽类自身具有的构造方法。 这样就能屏蔽这种创建类对象的方式。
       类名 对象名 =  new 类名()
 
第一:屏蔽构造方法,设置成private的。  下面是外部类使用构造方法创建对象的报错信息
SingletonX singletonTest = new SingletonX();
【The constructor SingletonX() is not visible】
第二:自己内部new出一个 自己的对象唯一的对象 返回。

=============================下面是V1.0版本================================
public class SingletonX {
//私有化的构造方法,保证外部的类不能通过构造器来实例化 
private SingletonX() {}
//单例   实例变量
private static SingletonX singleton = null;
//获取单例对象实例   对外提供
public static SingletonX getInstance(){
if(singleton==null)
singleton = new SingletonX();
                                  return singleton;
}
}

=============================下面是V2.0版本================================
上面的代码在多线程的环境中不是线程安全的。
等当两个线程进入if (instance == null)时,两个线程都判断instance为空,接下来就会得到两个实例了。这不是我们想要的单例。
为了保证线程安全。使用synchronized  修饰一下
public static synchronized  SingletonX getInstance(){
}

此方法是可以解决问题。但是仔细想一想 其实只需要在第一次调用getInstance()的时候加锁就可以了。这样把synchronized  加在方法上会导致每次调用getInstance方法。
把synchronized  加到代码块上试一试吧
=============================下面是V2.5版本================================
//获取单例对象实例   对外提供
public static SingletonX getInstance() { 
         if (instance == null) {  
             synchronized (Singleton.class) {
             //再次判断是否为空 防止上面多线程的时候有多个线程进入了等待synchronized 如不再次进行为空判断依然会出现多个实例。
                 if (instance == null) {  
                     instance = new Singleton();  
                } 
             } 
         }
         return singleton;

=============================下面是V2.5版本================================
不过又听说java平台内存模型中有一个叫“无序写”(out-of-order writes)的机制。

instance = new Singleton(); 这行其实做了两个事情:
1、调用构造方法,创建了一个实例。
2、把这个实例赋值给instance这个实例变量。可问题就是,这两步jvm是不保证顺序的。也就是说。可能在调用构造方法之前,instance已经被设置为非空了。 
synchronized 能保障同一时间只有一个线程进入同步块。但是不能保证每次都能完整执行同步块,也就是执行了一部分就退出,让给其他线程来执行。  A线程执行了上面说的第2步退出
此时instance 不为空了,我也不知道它现在是一个什么值? B线程进来判断不为空 返回了一个没有调用构造方法实例出来的一个值。紧接着A线程继续调用构造方法返回真正的单例对象。 


解决方案:
就是要保障instance = new Singleton() 这个搞成原子性的。 引入一个Temp变量来保存创建出来的实例对象,如果没有完整创建,退出。B线程进来instance 依然是Null。

//获取单例对象实例
public static Singleton getInstance() {
     if (instance == null) {
         synchronized (Singleton.class) {          //1
             Singleton temp = instance;            //2
             if (temp == null) {
                 synchronized (Singleton.class) {  //3
                     temp = new Singleton();   //4   
                 }
                 instance = temp;                  //5     
             }
         }
     }
     System.out.println("我是解决无序写懒汉式单例!");
     return instance; 
}

=============================下面是V3.0版本================================

虽然实现了但是很乱,精简一下代码换个思路。
//饿汉式
  public class Singleton {     
      //单例变量 ,static的,在类加载时进行初始化一次,保证线程安全
      private static Singleton instance = new Singleton();   
     
      //私有化的构造方法,保证外部的类不能通过构造器来实例化。    
      private Singleton() {}
     
      //获取单例对象实例    
      public static Singleton getInstance() {
          System.out.println("我是饿汉式单例!");
          return instance;
      }
  }

代码分析:饿汉式单例,意思就是预先声明Singleton对象,这样带来的一个缺点就是:如果构造的单例很大,构造完又迟迟不使用,会导致资源浪费。

==========继续改进调用getInstance方法时再进行构造方法初始化对V4.0===========
  //内部类实现懒汉式
  public class Singleton {     
      private static class SingletonHolder{
          //单例变量 
          private static Singleton instance = new Singleton();
      }
     
      //私有化的构造方法,保证外部的类不能通过构造器来实例化。
      private Singleton() {}     
      //获取单例对象实例
      public static Singleton getInstance() {
          System.out.println("我是内部类单例!");
          return SingletonHolder.instance;
      }
  }

懒汉式(避免上面的资源浪费)、线程安全、代码简单。因为java机制规定,
内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy),
而且其加载过程是线程安全的(实现线程安全)。内部类加载的时候实例化一次instance

SingletonHolder是私有静态内部类,所以不会被其他类知道,同样,static语义也要求不会有多个实例存在。并且,JSL规范定义,类的构造必须是原子性的,非并发的,因此不需要加同步块。同样,由于这个构造是并发的,所以getInstance()也并不需要加同步。


欢迎探讨:QQ 350355139 设计模式一次搞定

参考资料:
http://blog.163.com/yanjingyu_happy/blog/static/111639566201364115047132/

http://devbean.blog.51cto.com/448512/203501/
分享到:
评论

相关推荐

    Easy搞定设计模式.pdf

    Easy搞定设计模式.pdf

    轻松搞定设计模式

    自己整理的简单,清晰,易于理解学习设计模式文档。如果你是新手。看完这三十多页的PPT,相信你可以轻松搞定常用的设计模式。

    最新Git与Github首篇巨作课程 Git&Github极速入门与攻坚实战结合课程 一次搞定Git.txt

    最新的Git与Github巨作课程,课程内容主旨分成了Git&Github极速入门与攻坚实战课程两部分,可以理解为一个是课程的详细教学篇,和一个精华缩减的集合。Git与Github教程详细介绍了Git的...一次性搞定Git与Github的学习。

    传智播客轻松搞定系列 C、C++、Linux、设计模式

    书中将介绍一些经典的设计模式,如单例模式、工厂模式、观察者模式等,这些模式可以提高代码的可读性、可维护性和可扩展性,帮助你写出更高质量的代码。 最后,《传智播客轻松搞定 Linux 基础篇》将引导你进入操作...

    新版设计模式.pdf

    - 单例模式:确保一个类只有一个实例,并提供一个全局访问点。 - 工厂模式:提供一个接口用于创建相关或依赖对象的家族,而无需指定具体类。 - 抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而...

    考研英语作文万能模板一次搞定.doc

    考研英语作文万能模板一次搞定.doc

    基于单例和抽象工厂及sql动态参数的CodeSmith多层模板

    今天又做了一个基于单例和抽象工厂及sql动态参数的CodeSmith多层模板,用到了单例设计模式和抽象工厂模式接口,根据个人业务需要可以进行动态修改生成自己所需要的代码,搭建.net多层代码不用1个小时就搞定。

    XP计算机名_IP_网关_DNS一次搞定

    在标题和描述中提到的"一次搞定"可能是指使用特定的工具,如压缩包中的"IP修改工具V1.4.exe"。这是一个可能的第三方软件,旨在简化上述设置过程,一次性完成所有配置。用户只需运行该工具,按照向导提示输入所需信息...

    一个23设计模式的搞笑解释

    5. **Singleton(单例模式)**: - **比喻**:假设你有六个美丽的妻子,但她们的丈夫都是你,你就是这个家庭中的唯一丈夫。 - **原理**:确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于资源管理...

    源码-一个实例搞定MATLAB界面编程

    - 通过`GUI`选项支持仅允许一个实例运行(即单例模式)。 - 实现了初始化代码、打开函数(`pjimage_OpeningFcn`)等核心组件。 #### 三、源代码详细分析 ##### 1. 函数定义 ```matlab function varargout = pjimage...

    一周搞定系列之模电数电全集

    举例:一周搞定51单片机视频教程 链接: https://pan.baidu.com/s/1c2cGGCg 密码: a9ng 一周搞定系列之模电数电全集 源享科技STM32高清视频教程 一周搞定系列之模电。cohf

    一次下载搞定,STM32F103各种外围电路合集(都有了)

    这个压缩包文件名为"2bc47797f34544d099d57cd8e786f3d9",很可能包含了关于STM32F103的多种外围电路设计实例和资料,方便开发者一次性获取所有必要的资源。 STM32F103系列拥有丰富的外设接口,包括但不限于: 1. **...

    一周搞定系列之51单片机_视频学习配套资料

    《一周搞定系列之51单片机_视频学习配套资料》是专为51单片机初学者设计的一套全面而实用的学习资源。这个压缩包包含了一系列与51单片机相关的进阶芯片资料和基础编程教程,旨在帮助学习者快速入门并提升技能。 51...

    一周搞定系列C语言_视频配套学习资料.zip

    【一周搞定系列C语言_视频配套学习资料.zip】是一个针对初学者设计的C语言学习资源包,虽然视频教程缺失,但包含了大量的C语言程序实例,是深入理解和掌握C语言编程的良好辅助材料。这个压缩包主要涵盖了C语言的基础...

    设计模式.pdf

    本书设计实例从面向对象的设计中精选出23 个设计模式,总结 了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达...本书分类描述了一组设计良好,表达清楚的软件设计模式,这些 模式在实用环境下有特别有用。

    关于Java23种设计模式的有趣见解

    - **定义**:单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。 - **例子**:比如你有六个美丽的妻子,她们共同拥有同一个丈夫——你。无论她们何时称呼“老公”,都是指同一个人。...

Global site tag (gtag.js) - Google Analytics