不好的解法一
![1b0d9b7fcf8be45fa0de54da6baf6442.png](https://i-blog.csdnimg.cn/blog_migrate/f411030856319cfc45542820e594a2c4.jpeg)
这个解法在多线程中使用是有风险的,可能会创建多个单例,怎么办呢,加同步锁呗。
不好的解法二
![fef00b1822cade79e286ea926a2bf631.png](https://i-blog.csdnimg.cn/blog_migrate/51144c307c72f2e6e2165bc041c3547d.jpeg)
但是这种解法仍有不好的地方,在每次通过属性Instance得到Singleton2的单例时,都会加上同步锁,也就是会反复上锁,而加锁是一个非常耗时的操作,在没有必要的时候应该尽量避免,因此这个解法还有优化的空间。
可行的解法一
![5ef9bbf50c95118e670f608fe988d71b.png](https://i-blog.csdnimg.cn/blog_migrate/0ef8abdb05bc5b1eacf481942735fd89.jpeg)
这种解法只是在上一个解法中,加了一个if判断。因为创建多个单例唯一有风险的地方就是单例还没有被创建出来的时候。所以只在第一次试图创建实例的时候需要加锁,实例创建出来后就不需要加锁操作了。因此,这个解法的时间效率比上一个要好很多。
但是这种解法嵌套太多,写起来还是太复杂了,其实还有另一种写法。
可行的解法二
![b40ab7e4c3fb54e410052dd163bc7cf7.png](https://i-blog.csdnimg.cn/blog_migrate/b6d166ecce56dcac7272f5618c7d31c4.jpeg)
C#静态构造函数有如下特性:
- 类最多只能有一个静态构造函数(可与实例构造函数共存),且不能带参数
- 静态构造函数不能有访问修饰符
- 不能访问实例成员,因此也不能使用this访问器
- 不能显式调用,系统自动调用
- 只要使用到该类(写到该类)就会执行一个过程(先执行静态字段赋值语句,然后执行静态构造函数),而这一过程由.Net运行时保证只执行一次
因此我们可以写如下代码实验
![4c5b1db9e323b26879af2a9760363a89.png](https://i-blog.csdnimg.cn/blog_migrate/b90b16cc42d8e7d4e0880efd6d3c9766.jpeg)
![0a70296b784e5949ea229af45552ff14.png](https://i-blog.csdnimg.cn/blog_migrate/f4ff95d9c4bdad47fa8482f605215c4f.jpeg)
![905c8c84cc04e01b54df67183e34eb39.png](https://i-blog.csdnimg.cn/blog_migrate/1f2c80308898795fdcf29253f72feda0.jpeg)
如果我首先用了该类执行了里面的静态方法,但是不用单例,这种写法也会给我们创建单例出来,即过早地创建单例,从而降低内存的使用效率。而下面的解法可以很好地解决这个问题。
可行的解法三
![7d038e3debb7708e49da110a78370fe5.png](https://i-blog.csdnimg.cn/blog_migrate/e8e25d15e0a901002401fb8fb3edc291.jpeg)
这种解法能实现按需创建单例,当然,如果单例较大,用Lazy也是可以的。
可行的解法四
如果不要属性,也不要延迟加载,那么可行解法二可以直接写成下面这种
![28ada38781960bdaf12ef45bb4538da3.png](https://i-blog.csdnimg.cn/blog_migrate/02b16fa662d648e44900679c672513cc.jpeg)
关于单例和静态类的区别可参考下面这个文章
https://blog.csdn.net/u014672511/article/details/79774847?utm_source=copyblog.csdn.net