1 单例模式

  

 //单例模式 类是密封的
    public sealed class Singlton
    {
        static Singlton instance = null;
        private Singlton() { }
        public static Singlton Instance
        {
            get 
            {
                if (null == instance)
                {
                    instance = new Singlton();
                }
                return instance;
            }
        }
    }
View Code

上面的代码存在一个大问题,线程安全问题,因为Singlton对象可能 不止一次被创建

比如当2个请求同时方式这个类的实例的时候,可以会在同一时间点上都创建一个实例,虽然一般不会出异常错误,但是确实就不会是单例了

 

解决方法:加锁

 //单例模式 类是密封的
    public sealed class Singlton
    {
        static Singlton instance = null;
        //private static readonly object _lock = new object();
        static System.Timers.Timer sysTimer = new System.Timers.Timer(6000);
        //private Singlton()
        //{
        //    //这种单例模式有个问题,无法实现更新单例的值,比如instance对象希望从数据库获取一个列表,但这个列表可能经常变化
        //    instance = new Singlton();
        //}
        //为了解决上面的问题,引入时间触发器的概念
         static Singlton()
        {
            sysTimer.AutoReset = true;
            sysTimer.Enabled = true;
            sysTimer.Elapsed += new ElapsedEventHandler(SysTimer_Elapsed);
        }
        //被订阅了Elapsed 时间的SysTimer_Elapsed,每个一段时间就会去重新获取数据列表
        static void SysTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Reload();
        }
        internal static void Reload()
        {
            //todo(从数据库获取列表)
        }
        public static Singlton Instance
        {
            get 
            {
                //lock (_lock)
                //{
                    if (null == instance)
                    {
                        instance = new Singlton();
                    }
                    return instance;
                }
               
            //}
        }
    }
View Code

另外这是一个大牛写的泛型单例模式:

/// <summary>
    /// 泛型单例基类
    /// </summary>
    public abstract class Singleton<TEntity> where TEntity : class
    {
        private static readonly Lazy<TEntity> _instance
          = new Lazy<TEntity>(() =>
          {
              var ctors = typeof(TEntity).GetConstructors(
                  BindingFlags.Instance
                  | BindingFlags.NonPublic
                  | BindingFlags.Public);
              if (ctors.Count() != 1)
                  throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor.", typeof(TEntity)));
              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(TEntity)));
              return (TEntity)ctor.Invoke(null);
          });

        public static TEntity Instance
        {
            get { return _instance.Value; }
        }
    }
View Code

只要实现的类直接继承就可以了

 

总体来说:单例模式涉及的东西可能很多:

私有构造函数,静态构造函数,静态字段,readonly和const,锁,延时创建对象等

  /// <summary>
    /// 标记为sealed,可以防止被继承然后在子类实例化(使用在静态私有字段上new一个实例来保证该类在第一次被调用的时候创建一个单例)
    /// //这种方式缺点:C#规范只是在IL里标记该字段为静态字段,也就是说静态字段可能在第一次使用的时候创建,也有可能没使用会创建,所以不能保证创建该实例的具体啥时候,
    /// </summary>
    public sealed class Singleton2
    {
        // 在静态私有字段上声明单例
        private static readonly Singleton2 instance = new Singleton2();

        // 私有构造函数,确保用户在外部不能实例化新的实例
        private Singleton2() { }

        // 只读属性返回静态字段
        public static Singleton2 Instance
        {
            get
            {
                return instance;
            }
        }
    }

 

所以一般使用volatile ,用来确保instance在被访问之前被赋值实例

 public sealed class Singleton
    {
        // 依然是静态自动hold实例
        private static volatile Singleton instance = null;
        // Lock对象,线程安全所用
        private static object syncRoot = new Object();

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new Singleton();
                    }
                }

                return instance;
            }
        }
    }

 

静态构造方法:

 public class Singleton3
    {
        //因为声明了静态构造函数,所以第一次访问该类之前,不会被初始化
        private static readonly Singleton3 instance = new Singleton3();
        /// <summary>
        /// 声明该静态构造函数作用是为了删除IL里BeforeFieldInit标记,确保延迟实例化
        /// </summary>
        static Singleton3()
        { }
        //
        private Singleton3() { }
    }

 

Lazy方式:

 public class Singleton
    {
        // 因为构造函数是私有的,所以需要使用lambda
        private static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(() => new Singleton());
        // new Lazy<Singleton>(() => new Singleton(), LazyThreadSafetyMode.ExecutionAndPublication);

        private Singleton()
        {
        }

        public static Singleton Instance
        {
            get
            {
                return _instance.Value;
            }
        }
    }

注意: Lazy的默认构造器只能调用传入泛型类型T的public构造函数的,但是这是因为在本类内部,所以本类的私有构造是可以的,

上面注释的部分是设置线程安全的,但是因为Lazy默认就是线程安全的,所以不用特别设置

 

上面这个版本的泛型版本:

 public abstract class Singleton<T> where T : class
    {
        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; }
        }
    }

 

总结下:

1 声明抽象类,以便不能直接使用,必须继承该类才能用

2 使用Lazy<T>作为_instance,T就是要实现单例的继承类

3 单例类的构造函数必须是私有的,所以要加验证,一旦验证通过,就Invoke这个私有的无参构造函数

4 Instance属性返回唯一一个T的实例

单例缺点:
1 增加系统开销,因为每次使用类的实例都要检查实例是否存在,可以通过静态实例来解决

2 无法销毁对象,单例模式的特性决定了只有它自己才能销毁对象实例

posted @ 2016-07-04 16:03  那就让我这样吧  阅读(173)  评论(0编辑  收藏  举报