设计模式—单例模式

单例模式主要特点不是根据客户程序调用生成一个新的实例,而是控制某个类型的实例数量唯一一个。即单例模式就是保证在整个应用程式的生命周期中,在任何时刻,被知道的类只有一个实例,并为客户程序提供一个获取该实例的全景访问点

一.经典模式

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

namespace ConsoleApplication1
{
    public class Instance
    {
        //经典模式
        private static Instance instance;
        private Instance()
        {

        }
        public static Instance GetInstance()
        {
            if (instance == null)
            {
                instance = new Instance();
            }
            return instance;
        }      
    }
}

 解释:在经典模式下,没有考虑多线程并发获取实例的问题,即有可能出现两个线程同时获取实例,且此时为null时,会出现两个线程创建了两个实例,违反了单例模式的规则。

 

二.多线程下的单例模式

 1.Lazy(懒汉) 模式

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

namespace ConsoleApplication1
{
    public class Instance
    {
        //Lazy(懒汉)模式
        private static Instance instance;
        private static object _lock = new object();
        private Instance()
        {

        }
        public static Instance GetInstance()
        {
            if (instance == null)
            {
                lock (_lock)
                {
                    if (instance == null)
                    {
                        instance = new Instance();
                    }
                }
            }
            return instance;
        }    
    }
}

解释:上述代码使用双重锁定方式较好的解决了多线程下的单例模式实现,先看内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。再看外层的if语句块,这使得 每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开 销。两次判断Instance==null是第二个是为了万一一个线程刚锁定时,已经有一个线程实例了一个Instance,此时如果不判断会又实例一个

2.饿汉模式(特点:自己主动实例)

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

namespace ConsoleApplication1
{
    public class Instance
    {
        private static readonly Instance instance = new Instance();
        private Instance() { }
        public static Instance GetInstance() {
            return instance;
        }
    }
}

解释:上面使用的readonly关键可以跟static一起使用,用于指定该常量是类别级的,它的初始化交由静态构造函数实现,并可以在运行时编译。在这种模 式下,无需自己解决线程安全性问题,CLR会给我们解决。由此可以看到这个类被加载时,会自动实例化这个类,而不用在第一次调用 GetInstance()后才实例化出唯一的单例对象。

不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。

posted @ 2014-08-13 11:11  细数青春  阅读(217)  评论(0编辑  收藏  举报