单例模式

单例模式

单例模式是最简单的一种模式了相对于其他模式,他的主要目的就是为了保证一个类只能有一个实例。这在编程当中也是非常常见的。比方说window任务管理器,就只能开一个,比方说我们开发的时候弹出的窗体,也只允许有一个。

我们常见的创建对象的方法是直接new一个,如下:

Singleton instance=new Singleton();
这种方式的结果的,在不同的环境中或者在同一个个环境中我们想new几个就new几个,对象的产生是自由的,要想产生单个对象,可以通过私有构造器来实现,我们可以写一个方法,在每次new之前,先判断一下,如果没有这个对象,就new一个,如果有就不需要再创建了。如下:

 class Singleton
    {
        private static Singleton instance;
        private Singleton()
        {

        }
        private static Singleton CreateInstance()
        {
            if(instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }

上述方法再单线程下几乎是很完美了,但是我们也需要注意几点,单例模式的创建方法只管对象的创建,至于该对象的销毁,一般由clr自动回收的。,当然有些非托管的资源在销毁的时候可能需要手动销毁掉。

需要注意的是单例模式不应该支持ICloneable接口,这可能会导致多个对象得实例。(该接口是实例的克隆接口,在拷贝对象的时候同样可能还是会产生多个实例,也就违背单例模式的初衷了)。单例模式也不应该支持序列化操作,因为对象的创建除了通过构造器以外,也可以通过序列化实现,这样也会出现与单例模式想悖的情况。还有一个就是多线程,很多情况下,在多线程环境中就得考虑并发,比方我启动两个线程,这两个线程同时启动也可能产生两个实例,还是违背了单例的初衷,而且在并发访问资源的同时,会出现各种意想不到的问题,解决办法还是加锁。代码如下:

  class Singleton
    {
        public static volatile Singleton instance;//多任务环境下各任务间共享的标志volatile
        private static object obj = new object();
        private Singleton()
        {

        }
        private static Singleton CreateInstance()
        {
            if (instance == null)//先检查实例是否存在,如果不存在才进入下面的同步块  
            {
                lock (obj)//同步块,线程安全的创建实例  
                {
                    if (instance == null)//再次检查实例是否存在,如果不存在创建实例  
                    {
                        instance = new Singleton();
                    }
                }
            }
           
            return instance;
        }
    }

这里使用了双重判定,需要说明一下,之所以使用两个if,是因为在多线程中(比方说两个线程),由于刚开始的时候,假设两个线程同时到达,同时调用CreateInstatce()方法,这个时候两个instance都为null,那么两个线程都会通过第一重if语句instance == null判断,当进入第一个if语句后,由于加锁的存在,第二个线程在外等待,第一个线程进入第二重判断,这个时候new出一个instance对象,然后执行结束,第一个线程退出锁,这个时候第二个线程进入锁,如果不对他进行判定instace==null的话,他还是会直接执行instance = new Singleton();这句话,相当于又new出了一个instance对象,还是违背了单例的设计模式的初衷。当然,这个如果细心考虑的话,如果用第二个if就行了,因为,在第二个if执行的时候,一个线程new出一个instance实例,当他退出的时候,在内存里已经有一个instance实例了,由于静态资源,也不会立马释放,当第二个线程进入时候,由于instance不为空,所以第二个if其实肯定进不去,但是这里再判断一次,其实是考虑多线程情况下,线程同步执行的情况下的性能问题,想象一下,第二个线程进入的时候,其实资源已经不为空了,这个时候我也没必要在加锁判断了,只需要在锁外面判断就行了,加锁和解锁本身就是耗费性能的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值