设计模式-单利模式

设计模式-单利模式

一、单例模式
确保一个类仅有一个实例,并提供一个全局访问点,避免一个全局使用的类频繁的创建和销毁。

二、何时使用
一个公司只有一个老板
一个学校只有一个校长
操作系统只有一个任务管理器

三、如何实现
下面使用C#代码展示

    public class Singleton
    {
        // 单例实例,声明为 instance,避免外部调用
        private static Singleton instance = null;

        // 将构造函数声名为 private 避免外部调用
        private Singleton()
        {

        }

        // 提供一个外部访问函数
        public Singleton GetInstance()
        {
            if (null == instance)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }

上面代码在单线程中是没问题的,但是在多线程中会存在线程不安全。
如果两个线程同时访问 GetInstance() 方法且 instance 为 空, 则 if (null == instance) 这个条件在两个线程判断都为 真(true),此时两个线程都会创建 Singleton 实例,破坏了我们的规则。

改进如下

    public class Singleton
    {
        // 单例实例,声明为 instance,避免外部调用
        private static Singleton instance = null;
        // 定义一个标示,确认线程安全
        private static readonly object locker = new object();
        // 将构造函数声名为 private 避免外部调用
        private Singleton()
        {

        }

        // 提供一个外部访问函数
        public Singleton GetInstance()
        {
            // 当第一个线程运行到这里时,此时会对 locker "加锁"
            // 当第二个线程运行到这里时,检测到 locker 对象为 "加锁" 状态,
            // 第二个线程就会挂起等待第一个线程执行结束
            // lock 语句运行完之后,会对该对象 "解锁"
            lock (locker)
            {
                if (null == instance)
                {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    }

改进后的代码是线程安全了,在多线程调用过程中也不会出现多次创建的问题了,但是却产生了新的问题,当多个线程访问 GetInstance() 函数,运行到 lock (locker) 的时候,每个线程都会在这里 “加锁”,其他线程需要在此挂起等待,如果此时 instance 已经创建过了,不为空,其他线程在此挂起等待,浪费了多线程的效率,还需要再次修改

改进如下

    public class Singleton
    {
        // 单例实例,声明为 instance,避免外部调用
        private static Singleton instance = null;
        // 定义一个标示,确认线程安全
        private static readonly object locker = new object();
        // 将构造函数声名为 private 避免外部调用
        private Singleton()
        {

        }

        // 提供一个外部访问函数
        public Singleton GetInstance()
        {
            // 每个线程运行到这里先判断是否为空,如果不为空
            // 则直接跳过此模块
            if (null == instance)
            {
                // 当第一个线程运行到这里时,此时会对 locker "加锁"
                // 当第二个线程运行到这里时,检测到 locker 对象为 "加锁" 状态,
                // 第二个线程就会挂起等待第一个线程执行结束
                // lock 语句运行完之后,会对该对象 "解锁"
                lock (locker)
                {
                    if (null == instance)
                    {
                        instance = new Singleton();
                    }
                }
            }

            return instance;
        }
    }

优点:
内存中只有一个实例,减少了内存开销(一个对象频繁的创建、销毁 降低性能)
全局都可以轻松访问

缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值