首页 > 学院 > 开发设计 > 正文

《CLR via C#》读书笔记-线程同步(六)-C#中的单例模式

2019-11-06 06:24:47
字体:
来源:转载
供稿:网友

        单例模式是经常用到的,最常用的情况就是创建一个数据库连接。下面说一下C#的单例模式的实现方式

实现方式1

        最严谨的方式:

public sealed class Singleton{	//声明一个私有锁	PRivate static object m_lock = new object();		//单例变量的声明	private static Singleton s_value=null;		//初始化的相关工作	//这儿需要注意,构造器的是私有的	private Singleton(){			}		//返回一个单例模式	public static Singleton GetSingleton(){		//		if(s_value!=null) return s_value;				//获得私有锁		Monitor.Enter(m_lock);		if(s_value==null){			//这儿的写法是先声明一个temp,然后通过InterLocked进行赋值			//目的就是保证,先完成“完整的”初始化后,再将对象引用赋给s_value			//防止出现如下的情况:CLR先分配完Singleton的内存,然后将引用赋值给s_value,最后再调用构造器			Singleton temp=new Singleton();			InterLocked.Exchange(s_value,temp);		}		Monitor.Exit(m_lock);				return s_value;	}	}        上面的代码就是C#中最严谨的单例模式的代码。C#可以“正确”的实现单例模式,但是java不能保证在任何地方都能正常工作。其原因就是:JVM在GetSingleton方法中第一次读取时,将s_value读入寄存器中。进行到第二个if语句时,直接从寄存器中读取s_value的值。导致第二个if语句永远都是true。因此会存在多个线程同时创建Singleton对象,因此在Java中有如此表现。

实现方式2

        第一种方式较为繁琐,可直接利用CLR的一个特征:CLR保证类的构造器是线程安全的。因此可以使用粗暴的方式,如下:

public sealed class Singleton{		//单例变量的声明	private static Singleton s_value=new Singleton();		//初始化的相关工作	//这儿需要注意,构造器的是私有的	private Singleton(){			}		//返回一个单例模式	public static Singleton GetSingleton(){ return s_value;}}        这种方式简单粗暴。通过CLR的特征保证了线程安全,但是没有保证单例。因此这种方式不能称之为一个“单例模式”。因此对此方式进行修改

实现方式3

        根据方式2的修改,得到如下:

public sealed class Singleton{		//单例变量的声明	private static Singleton s_value=new Singleton();		//初始化的相关工作	//这儿需要注意,构造器的是私有的	private Singleton(){			}		//返回一个单例模式	public static Singleton GetSingleton(){		if(s_value!=null) return s_value;				//这儿会有竞争,有可能多个线程都进行到这步,创建了多个Singleton对象		//但是通过调用CompareExchange方法,只有一个Singleton对象,将其赋予s_value		Singleton temp=new Singleton();		InterLocked.CompareExchange(s_value,temp,null);				return s_value;	}}        这儿也会存在一个小问题,就在Singleton temp=new Singleton();这句,多个线程可能会创建多个Singleton对象,但是通过CompareExchange方法,可以保证只有一个Singleton对象,其他的会被GC回收掉。优点就是快

4其他

        系统提供了一个System.Layz类,基本信息如下,其主要目的就是延迟初始化(延迟加载)

public class Lazy<T>{	public Lazy(Func<T> valueFactory,LazyThreadSafeMode mode);	public bool IsValueCreated{get;}	public T Value{get;}}       使用的例子如下:

public static void Main(){	//定义一个延迟加载变量	Lazy<string> sLazy = new Lazy<string>(()=>DateTime.Now.ToString(),LazyThreadSafeMode.PublicationOnly);		Console.WriteLine(sLazy.IsValueCreated);	Console.WriteLine(sLazy.Value);	Console.WriteLine(sLazy.IsValueCreated);	Thread.Sleep(1000);	Console.WriteLine(sLazy.Value);}        在构造器中还有一个参数:LazyThreadSafeMode,其定义如下:

        从上之下:ExecutionAndPublication使用了双锁技术;None线程不安全;PublicationOnly使用了CompareExchange技术。       

       另外还有一个延迟加载的静态方法System.Threading.LazyInitializer方法


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表