文章1:

 一、多线程不安全方式实现

public sealed class SingleInstance

   {
       private static SingleInstance instance;
       private SingleInstance() { }
       public static SingleInstance Instance
       {
           get
           {
               if (null == instance)
               {
                   instance = new SingleInstance();
               }
               return instance;
           }
       }
   }

  sealed表示SingleInstance不能被继承。其实构造函数私有化已经达到了这个效果,私有的构造函数不能被继承。为了可读性,可以加个sealed。

不安全的单例指的是在多线程环境下可能有多个线程同时进入if语句,创建了多次单例对象。

   二、安全的单例模式

public sealed class SingleInstance

  {
      private static volatile SingleInstance instance;
      private static readonly object obj = new object();
      private SingleInstance() { }
      public static SingleInstance Instance
      {
          get
          {
              if (null == instance)
              {
                  lock (obj)
                  {
                      if (null == instance)
                      {
                          instance = new SingleInstance();
                      }
                  }
 
              }
              return instance;
          }
      }
  }

 加锁保护,在多线程下可以确保实例值被创建一次。缺点是每次获取单例,都要进行判断,涉及到的锁和解锁比较耗资源。

三、只读属性式

public sealed class SingleInstance

   {
       private static readonly SingleInstance instance = new SingleInstance();
       private SingleInstance() { }
       public static SingleInstance Instance
       {
           get
           {
               return instance;
           }
       }
   }

   借助readonly属性,instance只被初始化一次,同样达到了单例的效果。在Main函数执行第一句话之前,instance其实已经被赋值了,并不是预期的 只有到访问Instance变量时才创建对象。

如下代码:

class Program

   {
       static void Main(string[] args)
       {
           Console.WriteLine("Begin");
           var temp = SingleInstance.instance; ;
       }
   }
 
   public sealed class SingleInstance
   {
       public static readonly SingleInstance instance = new SingleInstance();
       private SingleInstance()
       {
           Console.WriteLine("初始化初始化!");
       }
       public static SingleInstance Instance
       {
           get return instance; }
       }
   }

  输出:

在执行第一句代码之前,实例已经被初始化。

解决方法是在SingleInstance中加上静态构造函数。

public sealed class SingleInstance

   {
       public static readonly SingleInstance instance = new SingleInstance();
       static SingleInstance() { }
       private SingleInstance()
       {
           Console.WriteLine("初始化初始化!");
       }
       public static SingleInstance Instance
       {
           get return instance; }
       }
   }

  在运行输出:

四、使用Lazy

public sealed class SingleInstance

   {
       private static readonly Lazy<SingleInstance> instance = new Lazy<SingleInstance>(() => new SingleInstance());
       private SingleInstance(){}
       public static SingleInstance Instance
       {
           get
           {
               return instance.Value;
           }
       }
   }

  Lazy默认是线程安全的。MSDN描述如下:

Will the lazily initialized object be accessed from more than one thread? If so, the Lazy<T> object might create it on any thread. You can use one of the simple constructors whose default behavior is to create a thread-safe Lazy<T> object, so that only one instance of the lazily instantiated object is created no matter how many threads try to access it. To create a Lazy<T> object that is not thread safe, you must use a constructor that enables you to specify no thread safety.

五、泛型单例

class Program

{
    static void Main(string[] args)
    {
        Console.WriteLine("Begin");
        mySingle.Instance.age = 500;
        Console.WriteLine(mySingle.Instance.age);
    }
}
 
public abstract class SingleInstance<T>
{
    private static readonly Lazy<T> _instance = new Lazy<T>(() =>
        {
            var ctors = typeof(T).GetConstructors(BindingFlags.Instance| BindingFlags.NonPublic| BindingFlags.Public);
            if (ctors.Count() != 1)
                throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor."typeof(T)));
            var ctor = ctors.SingleOrDefault(c => c.GetParameters().Count() == 0 && c.IsPrivate);
            if (ctor == null)
                throw new InvalidOperationException(String.Format("The constructor for {0} must be private and take no parameters."typeof(T)));
            return (T)ctor.Invoke(null);
        });
    public static T Instance
    {
      getreturn _instance.Value;}
    }
}
 
public class mySingle : SingleInstance<mySingle>
{
    private mySingle() { }
    public int age;
}
文章2:

什么是单例模式?

1.简单的思路就是, 创建对象单例的动作转移到另外的行为上面, 利用一个行为去创建对象自身, 如下:

   public class Singleton
{
private static Singleton _Singleton = null;
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
Console.WriteLine("被创建");
_Singleton = new Singleton();
}
return _Singleton;
}
}

这样写看上去是没有问题, 但是有没有那种可能, 同时两个动作都判断这个对象为空, 那么这个对象就会被创建2次?是的, 多线程中, 这样是无法保证单例。

就像这样, 同时创建多个线程去创建这个对象实例的时候, 会被多次创建, 这个时候, 对代码改进一下。

    public class Singleton
{
private static Singleton _Singleton = null;
private static object Singleton_Lock = new object(); //锁同步
public static Singleton CreateInstance()
{
lock (Singleton_Lock)
{
            Console.WriteLine("路过");
if (_Singleton == null)
{
              Console.WriteLine("被创建");
_Singleton = new Singleton();
}
}
return _Singleton;
}
}

调试代码:

               TaskFactory taskFactory = new TaskFactory();
List<Task> taskList = new List<Task>(); for (int i = 0; i < 5; i++)
{
taskList.Add(taskFactory.StartNew(() =>
{
Singleton singleton = Singleton.CreateInstance();
}));
}

结果:

上面, 我们创建了多个线程,同时去创建这个对象的实例, 在第二次,对象命名已经被创建了, 尽管只创建了一次满足了我们的需求, 但是我们已知对象被创建了, 还需要进来做不必要的动作吗?

我们都知道, 同步锁为了达到预期的效果, 也是损耗了性能的, 那么下面的输出, 很显然是没必要的动作, 所以我们优化一下。

    public class Singleton
{
private static Singleton _Singleton = null;
private static object Singleton_Lock = new object();
public static Singleton CreateInstance()
{
if (_Singleton == null) //双if +lock
{
lock (Singleton_Lock)
{
Console.WriteLine("路过。");
if (_Singleton == null)
{
Console.WriteLine("被创建。");
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}

结果:

很显然, 这样达到了我们的预期, 对象在被创建后, 就没必要做多余的行为。

利用静态变量实现单例模式

    public class SingletonThird
{
/// <summary>
/// 静态变量
/// </summary>
private static SingletonThird _SingletonThird = new SingletonThird(); public static SingletonThird CreateInstance()
{
return _SingletonThird;
}
}

是不是觉得很优雅, 利用静态变量去实现单例,  由CLR保证,在程序第一次使用该类之前被调用,而且只调用一次

PS: 但是他的缺点也很明显, 在程序初始化后, 静态对象就被CLR构造了, 哪怕你没用

利用静态构造函数实现单例模式

    public class SingletonSecond
{
private static SingletonSecond _SingletonSecond = null; static SingletonSecond()
{

_SingletonSecond = new SingletonSecond();
} public static SingletonSecond CreateInstance()
{
return _SingletonSecond;
}
}

静态构造函数:只能有一个,无参数的,程序无法调用 。

同样是由CLR保证,在程序第一次使用该类之前被调用,而且只调用一次

同静态变量一样, 它会随着程序运行, 就被实例化, 同静态变量一个道理。

文章分别转载自https://www.cnblogs.com/lh218/p/4713599.html、https://www.cnblogs.com/zh7791/p/7930342.html

(转)C# 单例模式的更多相关文章

  1. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  2. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  3. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  4. java设计模式之--单例模式

    前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...

  5. 设计模式C#合集--单例模式

    单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...

  6. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  7. GOF23设计模式之单例模式

    ·核心作用: -保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. ·常见应用场景: -Windows的Task Manager(任务管理器)就是很典型的单例模式 -Windows的Recy ...

  8. GJM : C#设计模式(1)——单例模式

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  9. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  10. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

随机推荐

  1. "添加与删除程序"报rundll32错误

    无法启动"添加与删除程序"系统报rundll32错误 系统反馈以下信息: rundll32.exe应用程序错误"0x00310030"指令 解决方法: 1.启动 ...

  2. BootstrapTable(附源码)

    Bootstrap结合BootstrapTable的使用,分为两种模试显示列表. 引用的css: <link href="@Url.Content("~/Css/bootst ...

  3. 【linux下多实例Tomcat+Nginx+redis+mysql环境搭建】

    一.搭建环境之前最好自己先创建一个文件夹,再次文件夹下在创建文件夹来安放项目包和Tomcat等应用以及性能测试监控的文件 1.项目存放地址: mkdir export (创建一个文件),mkdir a ...

  4. 【Python046--魔法方法:描述符】

    一.描述符的定义: 描述符就是将特殊类型的类的实例指派给另外一个类的属性 1.举例: 特殊类型的类要实现以下三个方法中的其中一个或者全部实现 * __get__(self,instance,owner ...

  5. Django框架 (一) 虚拟环境配置及简单使用

    虚拟环境 什么是虚拟环境 对真实的python解释器的一个拷贝版本 是事实有效的,可以独立存在运行解释python代码 可以在计算机上拷贝多个虚拟环境 为什么要使用虚拟环境 保证真实环境的纯净性 框架 ...

  6. Linux电源管理_autosleep--(五)【转】

    本文转载自:https://blog.csdn.net/wlsfling/article/details/46005409 1. 前言 Autosleep也是从Android wakelocks补丁集 ...

  7. 1-1.flutter学习笔记(一)git入门(msysgit图文安装)

    1.下载git-for-windows (1)常用的GitHub客户端msysgit,也就是git-for-windows. (2)登录官网 https://git-for-windows.githu ...

  8. 作为非计算机专业的学生,觉得 C 语言远比其他语言易于上手,正常吗?

    作者:invalid s链接:https://www.zhihu.com/question/26659552/answer/615531516来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...

  9. POJ 3903 Stock Exchange(LIS || 线段树)题解

    题意:求最大上升子序列 思路:才发现自己不会LIS,用线段树写的,也没说数据范围就写了个离散化,每次查找以1~a[i]-1结尾的最大序列答案,然后更新,这样遍历一遍就行了.最近代码总是写残啊... 刚 ...

  10. C++笔记(2017/2/9)

    this指针 this指针作用就是指向成员函数所作用的对象. 非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针. 静态成员函数中不能使用this指针. 静态成员 static 定义 ...