【C#设计模式-单例模式】

单例模式就是保证在整个应用程序的生命周期中,在任何时刻,被指定的类只有一个实例,并为客户程序提供一个获取该实例的全局访问点


一:经典模式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    /// <summary>
    /// 一、经典模式:
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// Singleton的构造函数必须是私有的,以保证客户程序不会通过new()操作产生一个实例,达到实现单例的目的;
        /// </summary>
        private Singleton(){ }

        /// <summary>
        /// 私有的静态全局变量instance来保存该类的唯一实例;
        /// </summary>
        private static Singleton instance;

        /// <summary>
        /// 提供一个全局函数访问获得该实例,并且在该函数提供控制实例数量的功能,
        /// 即通过if语句判断instance是否已被实例化,
        /// 如果没有则可以同new()创建一个实例;
        /// 否则,直接向客户返回一个实例
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }

        /// <summary>
        /// 测试属性
        /// </summary>
        public int Age { get; set; }

        public void GetShow()
        {
            this.Age = this.Age + 1;
            Console.WriteLine("我是一个单例对象:Age=" + Age);
        }
    }
}

1)该Singleton的构造函数必须是私有的,以保证客户程序不会通过new()操作产生一个实例,达到实现单例的目的;

2)因为静态变量的生命周期跟整个应用程序的生命周期是一样的,所以可以定义一个私有的静态全局变量instance来保存该类的唯一实例;

3)必须提供一个全局函数访问获得该实例,并且在该函数提供控制实例数量的功能,即通过if语句判断instance是否已被实例化,如果没有则可以同new()创建一个实例;否则,直接向客户返回一个实例。

在这种经典模式下,没有考虑线程并发获取实例问题,即可能出现两个线程同时获取instance实例,且此时其为null时,就会出现两个线程分别创建了instance,违反了单例规则。因此,需对上面代码修改。

二.多线程下的单例模式:

1、Lazy模式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    /// <summary>
    /// 二、多线程下的单例模式
  /// 1、Lazy模式
    /// </summary>
    public class Singleton2
    {
        private static Singleton2 instance2;
        private static object _lock = new object();

        private Singleton2()
        {

        }

        public static Singleton2 GetInstance(string thnum)
        {
            //外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,
            //因为只有实例为空时(即需要创建一个实例),才需加锁创建,
            //若果已存在一个实例,就直接返回该实例,节省了性能开销
            if (instance2 == null)
            {
                //Console.WriteLine("object is null" + thnum);
                lock (_lock) 
                {
                    //内层的if语句块,使用这个语句块时,先进行加锁操作,
                    //保证只有一个线程可以访问该语句块而保证只创建了一个实例
                    if (instance2 == null)
                    {
                        //Console.WriteLine("object not null" + thnum);
                        instance2 = new Singleton2();
                        instance2.Age = 0;
                    }
                }
            }
            return instance2;
        }

        /// <summary>
        /// 测试属性
        /// </summary>
        public int Age { get; set; }

        public void GetShow(string thnum)
        {
            this.Age = this.Age + 1;
            Console.WriteLine("我是一个单利对象:Age=" + Age+" 线程:"+thnum);
        }

    }
}

上述代码使用了双重锁方式较好地解决了多线程下的单例模式实现。

内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。

外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开销。

2.饿汉模式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    /// <summary>
    /// 二、多线程下的单例模式
    /// 2、饿汉模式
  /// 这种模式的特点是自己主动实例。
    /// </summary>
    public class Singleton3
    {
        /// <summary>
        /// 主动实例
        /// </summary>
        private static readonly Singleton3 instance = new Singleton3();

        private Singleton3()
        {

        }

        public static Singleton3 GetInstance()
        {
            return instance;
        }
    }
}

测试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("一、经典模式:测试");
            //Singleton s = new Singleton(); Error 编译器检测出现错误
            Singleton s = Singleton.GetInstance();
            s.GetShow();
            Singleton s1 = Singleton.GetInstance();
            s1.GetShow();
            Singleton s12 = Singleton.GetInstance();
            s12.GetShow();

            Console.WriteLine("二、多线程下的单例模式>Lazy模式:测试");
            Thread thr1 = new Thread(x => {
                Singleton2 s2 = Singleton2.GetInstance("thr1");
                s2.GetShow("thr1");
                s2.GetShow("thr1");
            });
            thr1.Start();
            Thread thr2 = new Thread(x => {
                Singleton2 s22 = Singleton2.GetInstance("thr2");
                s22.GetShow("thr2");
            });
            thr2.Start();
            Console.Read();
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值