文档章节

(转)C# 单例模式

o
 osc_1ee7cxmx
发布于 2018/08/06 15:06
字数 1351
阅读 0
收藏 0

精选30+云产品,助力企业轻松上云!>>>

文章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
     {
       get return  _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
o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

SnailSVN Pro for mac(SVN客户端) v1.9.9

macw为您带来SnailSVN Pro for mac ,SnailSVN Mac版是一款类似于 TortoiseSVN 的 Apache Subversion(SVN)客户端,与 Finder 紧密集成。SnailSVN Mac版允许你从 Finder 的上下文菜单中快速...

单手绕月
11分钟前
0
0
python网络编程(进程与多线程)

multiprocessing模块   由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。   multiprocessing包是Pytho...

osc_ky74f26k
11分钟前
0
0
CentOS7 redis5.0高可用部署

概述 Redis Sentinel为Redis提供高可用性。Redis Sentinel是一个分布式系统,Sentinel本身设计为在有多个Sentinel进程协同合作的配置中运行。具有多个Sentinel进程进行协作的优点如下: 1、当...

紅顏為君笑
12分钟前
0
0
Ocelot简易教程(四)之请求聚合以及服务发现

上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能。希望能对大家有所帮助。 作者:依乐祝 原文地址:https://www...

osc_zo0djpuu
13分钟前
0
0
leetcode63(不同路径 II)--Java语言实现

求: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在...

拓拔北海
13分钟前
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部