设计模式研究:单例
2011-11-06 15:25
197 查看
最近面试了很多兄弟,工作经验一般在2-3年,几乎所有的人都能对单例进行一般的解释,但是真正让他们手写一段单例代码的时候,能写得清楚明白的人就没几个了。下面我们一起来总结一下怎么写出一个好的单例。[源代码从这里下载]
目录
一、非线程安全的单例
二、未采用延迟加载的单例
三、采用线程同步方法实现的单例
四、采用双重锁实现的单例
五、【结论】采用原子操作实现的单例
六、使用单例模式的注意事项
一、非线程安全的单例:
这种写法存在的问题是,当并发调用GetInstance属性的时候,由于多个线程同时进入了if判断,从而造成返回多个Singleton对象的隐患。这自然就有违我们的单例模式了。
二、未采用延迟加载的单例:
由于采用框架特性,这种写法确实是线程安全的,但是类型一旦加载,单例对象就已经存在,造成多余开销,如果构造函数耗时比较长的话,影响就更为突出了。
三、采用线程同步方法实现的单例:
线程安全了,也延迟加载了,但是新的问题又来了,由于GetInstance方法在任何时候都只允许一个线程进入,带来的性能损失是不可忽视的。
四、采用双重锁实现的单例:
这样实现总该完美了吧,线程安全、延迟加载、效率都没有问题。但是如此写法稍显臃肿,就仅仅为了实现一个单例,搞了这么大一串括号,还为此引入了一个syncObj对象,还有更好的实现方式吗?
五、【结论】采用原子操作实现的单例:
这种写法可以解决以上提到的所有问题,唯一需要提醒一点的是,在调用原子操作之前的判断语句是必不可少的,因为一旦执行CompareExchange方法必然会调用Singleton类型的构造函数,虽然不会引发多个instance对象的问题,但是会造成性能损失,如果构造函数耗时过长,影响将更为严重,所以在调用原子操作之前,先进性单例的判断,就能解决以上问题。
六、使用单例模式的注意事项:
1:如果系统内存在多种类型的单例,那么这些单例之间不应该存在依赖关系 。如果确实存在非依赖不可的单例,证明你在设计上将不应该单例的对象单例了。或者是把你的设计把本应该一个单例的拆分为了多个单例。
2:一个类是否应该使用单例模式,不应该由类自己决定,而应该由类的使用者来决定。
目录
一、非线程安全的单例
二、未采用延迟加载的单例
三、采用线程同步方法实现的单例
四、采用双重锁实现的单例
五、【结论】采用原子操作实现的单例
六、使用单例模式的注意事项
一、非线程安全的单例:
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton GetInstance { get { if(null == instance) { instance = new Singleton(); } return instance; } } }
这种写法存在的问题是,当并发调用GetInstance属性的时候,由于多个线程同时进入了if判断,从而造成返回多个Singleton对象的隐患。这自然就有违我们的单例模式了。
二、未采用延迟加载的单例:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance { get { return instance; } } }
由于采用框架特性,这种写法确实是线程安全的,但是类型一旦加载,单例对象就已经存在,造成多余开销,如果构造函数耗时比较长的话,影响就更为突出了。
三、采用线程同步方法实现的单例:
public class Singleton { private static Singleton instance; private Singleton() { } [MethodImpl(MethodImplOptions.Synchronized)] public static Singleton GetInstance() { if (null == instance) { instance = new Singleton(); } return instance; } }
线程安全了,也延迟加载了,但是新的问题又来了,由于GetInstance方法在任何时候都只允许一个线程进入,带来的性能损失是不可忽视的。
四、采用双重锁实现的单例:
public class Singleton { private static readonly object syncObj = new object(); private static Singleton instance; private Singleton() { } public static Singleton GetInstance { get { if (null == instance) { lock (syncObj) { if (null == instance) { instance = new Singleton(); } } } return instance; } } }
这样实现总该完美了吧,线程安全、延迟加载、效率都没有问题。但是如此写法稍显臃肿,就仅仅为了实现一个单例,搞了这么大一串括号,还为此引入了一个syncObj对象,还有更好的实现方式吗?
五、【结论】采用原子操作实现的单例:
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton GetInstance { get { if (null == instance) { System.Threading.Interlocked.CompareExchange(ref instance, new Singleton(), null); } return instance; } } }
这种写法可以解决以上提到的所有问题,唯一需要提醒一点的是,在调用原子操作之前的判断语句是必不可少的,因为一旦执行CompareExchange方法必然会调用Singleton类型的构造函数,虽然不会引发多个instance对象的问题,但是会造成性能损失,如果构造函数耗时过长,影响将更为严重,所以在调用原子操作之前,先进性单例的判断,就能解决以上问题。
六、使用单例模式的注意事项:
1:如果系统内存在多种类型的单例,那么这些单例之间不应该存在依赖关系 。如果确实存在非依赖不可的单例,证明你在设计上将不应该单例的对象单例了。或者是把你的设计把本应该一个单例的拆分为了多个单例。
2:一个类是否应该使用单例模式,不应该由类自己决定,而应该由类的使用者来决定。
相关文章推荐
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- Java研究之学习设计模式-简单工厂模式详解
- 设计模式研究
- 设计模式的7大原则,最近正研究设计模式呢
- 设计模式之Factory深入研究(转)
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- 设计模式研究(三)Proxy与Adapter
- Java多线程技术研究(四)-Callable,Future/FutureTask,及Future设计模式
- 设计模式 研究 - 观察者模式 有时间跟新上来
- 算法,设计模式,数据结构,多线程以及研究领域的深入是我研究生阶段要完成的任务
- Java设计模式之外观模式研究
- struts2源码研究之设计模式准备
- 设计模式研究(二)-Singleton