剑指Offer面试题2 实现单例模式

实现单例模式主要有5种方法,分别是定义静态实例(只适用于单线程),两种加锁方式(一种消耗较大,一种过于复杂),以及重点的两种使用静态构造函数的方法。

依赖静态构造函数实现单例01:

public sealed class Singleton1
{  
   private static Singleton1  instance = new Singlenton1;
   public  static Singleton1  Instance{get{ return instance; }}

}

其中实例在初始化的时候就已经创建好,保证了只有一个实例。

依赖静态构造函数实现单例 02:

public sealed class Singleton
{
  public static Singleton Instance 
  { get { return Nested.instance; } }

  class Nested
  {
     internal  static Singleton2 instance = new Singleton();
  }
}

此为方法01的优化,添加了一个内部类Nested,由于Instance是一个静态属性,只有当其被用到时才会触发get,将Singleton类实例化。

不推荐的其他三种实现方法:

01.通过判断变量instance的状态来创建实例,在多线程无法使用

public sealed class Singleton
        {
            private static Singleton instance = null;
            public static Singleton Instance { 
                get{ 
                    if(instance == null)
                    instance = new Singleton(); 
                    return instance;
                } 
            }
        }

02.在01的基础上加锁来保证在多线程上的使用,但频繁加锁会导致效率变低

public sealed class Singleton
        {
            private static object obj = new object();
            private static Singleton instance = null;
            public static Singleton Instance
            {
                get 
                {
                    lock (obj)
                    {
                        if (instance == null)
                            instance = new Singleton();
                        return instance;
                    }
                }
            }
        }

03.在02的基础上增加了对instance的判断,使加锁的频率下降,但代码过于繁琐

public sealed class Singleton
        {
            private static object obj = new object();
            private static Singleton instance = null;
            public static Singleton Instance
            {
                get
                {
                    if (instance == null)
                    {
                        lock (obj)
                        {
                            if (instance == null)
                                instance = new Singleton();
                        }
                    }
                    return instance;
                }
            }
        }

 

由以上可知,实现单例最高效的方法是依赖静态构造函数,关于静态构造函数本人找到一个颇有代表性的面试题:

public class A
{
    public static readonly int x;
    static A()
    {
        x = B.y + 1;
    }
}
 
class B
{
    public static int y = A.x + 1;
 
    static void Main(string[] args)
    {
        Console.WriteLine("x:{0},y:{1}。", A.x, y);
        Console.ReadLine();
    }
}
//x:1 y:2

此题对静态实例的操作顺序进行了考察

C#高效编程里说到,这样一段话:
创建某个类型的第一个实例时,所进行的操作顺序为:
1.静态变量设置为0
2.执行静态变量初始化器
3.执行基类的静态构造函数
4.执行静态构造函数
5.实例变量设置为0
6.执行衯变量初始化器
7.执行基类中合适的实例构造函数
8.执行实例构造函数

详解如下:

1、首先,每一个项目有且只能有一个静态类的main函数作为入口函数。
而入口函数是最最先执行的。
2、由于main函数在B类里面,首先会初始化B类。而类的初始化顺序是:类里的静态变量,然后执行静态构造函数。
3、运行起先执行public static int y = A.x + 1;这个,执行这个的时候,先把y初始化为0.然后计算y的值。
4、计算y的值的时候,调用了A的静态变量x。那么就先初始化A类。
5、初始化A类时首先去执行public static readonly int x;执行这句,先把x初始化为0.
6、执行完接着执行A的静态构造函数x = B.y + 1;这是y还是初始化0.
7、计算得到x=1.然后回到public static int y = A.x + 1;得到y=2
8、然后再执行main函数。得出结果x=1,y=2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值