zoukankan      html  css  js  c++  java
  • 『创建型』单例模式Singleton学习笔记

    建议大家直接去看参考的文章,因为我在这里所记录的主要是从这几篇文章中学到的,以及自己的实现。

    参考:

    1. http://www.cnblogs.com/tomxu/archive/2011/12/19/2291448.html
    2. http://yinlei555.iteye.com/blog/707986 「static与线程安全」

    目的:保证一个类只有一个实例,并提供一个访问它的全局访问点。

    笔记:

    因为单例模式可以说是整个设计模式中最简单的一种模式了,所以其实现的方式也很多,当然,这其中所考查的知识点也很多。

    首先,为了保证不被在类外面实例化,就要使用私有构造函数。即使用private来标注构造函数。

    其次,为了保证不被子类继承后实例化,可以使用sealed来限制继承。当然,如果需要使用子类,而一般不会去尝试实例化基类的话,是可以不使用sealed的。ps:做为基类的存在,一般不建议使用单例模式。

    然后,为了保证外面可以得到一个实例化后的对象,我们可以使用static来标注一个类型为当前类的属性对象,并根据需要对其初始化的过程进行控制,以便来达到只有一个实例可以被返回的作用。这里也就所谓的全局访问点了。

    最后,如果是运行在多线程环境中的话,还要考虑线程安全,以及可能存在的创建多个的问题。所谓的线程安全,更多的是指多线程环境中共享资源的安全。

    几种实现方式:

    「实现方式一」

    笔记:

    这种实现方式在多线程环境下,可能会是不好用的,但是也不会出现异常。也就是说,如果同一时间点,有多个线程都要实例化这个对象的化,就会有多个实例出现。

    这里所谓的在多线程环境中不好用,是因为实例的创建是在属性的GET方法中,这表示着,当同一时间点,多个线程同时访问同一个从未被实例化过的单例对象时,因为之前这个对象是没有被实例化过的,所以就会一起实例化它,从而导致的多个实例对象共同存在的现象。

    这里如果是使用单一核心的CPU的话,应该也是不存在多线程同一时间创建多个单例对象的情况。因为所谓的多线程并发操作实质上是对CPU的执行时间的线性分配上,也就是说,在单一核心CPU的情况下,多线程并发实质上也是线性执行的。所以说,在单一核心CPU的时候,应该是不会存在这种问题的。

    private:private 关键字是一个成员访问修饰符。 私有访问是允许的最低访问级别。 私有成员只有在声明它们的类和结构体中才是可访问的。

    static:声明属于类型本身而不是属于特定对象的静态成员。

    sealed:此修饰符会阻止其他类从该类继承。

    使用sealed标记类的原因,是为了防止被继承后在子类实例化。

    「实现方式二」

    笔记:

    这里与第一个方式不同的地步在于声明实例的时候,就使用new关键字,来实例化。这样可以保证在第一次使用这个类的时候,就可以有一个实例在,并且不会有第一个实现的那种多线程的情况出现。

    这种方式根据出处(http://www.cnblogs.com/tomxu/archive/2011/12/19/2291448.html)中所说的一个不是很好的地方在于我们不能保证在IL里,这个字段是什么时候被创建。

    当然,在现在看来,如果不是对性能有特别的要求的话,这个还是可以接受的。

    readonly:声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中。也就是说,是只读的对象,只在第一次实例化的时候赋值以便初始化。

    「实现方式三」

    笔记:

    这个方法与前两种不同的地方在于在实例化对象之前,先Lock一个用做线程安全的对象。

    使用这个对象的时候,就可以保证在一个线程使用单例的时候,不会被其他线程改变,以确保在多线程同步的情况下的资源共享的安全。

    volatile:指示一个字段可以由多个同时执行的线程修改。 声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。 这样可以确保该字段在任何时间呈现的都是最新的值。通常用于由多个线程访问但不使用 lock 语句对访问进行序列化的字段。

    「实现方式四」

    笔记:

    这里根据原文的解释,使用静态构造方法可以有效的控制对象的实例化过程,可以阻止IL在代码使用这个类之前实例化它。

    「实现方式五」

    笔记:

    感觉上与第四种差不多,细想下,还是一定有区别的,不然就使用第四种就好了。

    这一种与第四种都是利用了静态方法在何时调用这一个特性来控制IL在调用这个类之前不去实例化这个对象。

    静态构造函数用于初始化任何 静态 数据,或用于执行仅需执行一次的特定操作。 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。

    「实现方式六」

    笔记:

    lambda函数的说明:「()」表示没有传入参数,也就是说,当调用这个lambda函数的时候,会实例化一个Singleton对象。

    lazy:提供对延迟初始化的支持。

    lazy.value:     获取当前 Lazy(Of T) 实例的延迟初始化值。

  • 相关阅读:
    WriteFile函数
    良好的动态内存申请与释放
    只需一条命令,快速在Windows 10上关闭Linux
    盘点程序员过年最怕被问的问题:薪资问题首当其冲,对象问题紧追其后
    程序员为什么是吃青春饭,而不是像医生律师一样越老越值钱?
    Linux网络配置的三种方法,手把手教你,一看就会!
    应届程序员VS往届程序员:当面对HR和领导时,此时的内心活动是这样的...
    MySql数据在磁盘上到底是怎么存储的?被存储的数据怎么查找?
    如何写出高质量的代码?优秀的程序员都是这样做的
    哼!MySQL 8.0不讲武德,给我挖坑!
  • 原文地址:https://www.cnblogs.com/sitemanager/p/2427448.html
Copyright © 2011-2022 走看看