设计模式(一)Singlton
- 单例定义:
确保一个类只有一个实例,并提供全局访问点。
- 适用场景:
1.) 当系统中某个类必须仅有一个实例对象,同时访问该系统的所有访问者必须访问同一个实例对象时,且该对象实例自身占用资源又不大时。
2.) 在C/s应用程序中,当我们要保证某一个非模式窗口,只能显示一个实例时。
- 举例适用场景:
线程池(threadpool)、缓存(cache)、对话框、处理编好设置和注册表(registry)的对象、日志对象,充当打印机、显卡等设备的驱动程序对象。这些类对象只能有一个实例,如果造出多个实例,就会导致许多问题产生,例如:程序的行为异常、资源适用过量,或者是不一致的结果。
- 实现推荐方案:
1 /// <summary> 2 /// Description of SiteSettings. 3 /// </summary> 4 public class SiteSettings 5 { 6 private static SiteSettings instance=null; 7 private static object locker=new object(); 8 9 private SiteSettings() 10 { 11 } 12 13 public static SiteSettings Instance { 14 get { 15 if(instance==null) 16 { 17 Console.WriteLine("Install equals null."); 18 lock(locker) 19 { 20 if(instance ==null) 21 { 22 Console.WriteLine("new SiteSettings instance."); 23 instance=new SiteSettings(); 24 } 25 } 26 } 27 return instance; 28 } 29 } 30 31 private bool siteClosed=false; 32 33 public bool SiteClosed { 34 get { return siteClosed; } 35 set { siteClosed = value; } 36 } 37 }
调用:
1 class Program 2 { 3 public static void Main(string[] args) 4 { 5 Console.WriteLine("Hello World!"); 6 7 // TODO: Implement Functionality Here 8 9 Console.WriteLine(SiteSettings.Instance.SiteClosed); 10 Console.WriteLine(SiteSettings.Instance.SiteClosed); 11 SiteSettings.Instance.SiteClosed=true; 12 Console.WriteLine(SiteSettings.Instance.SiteClosed); 13 14 Console.Write("Press any key to continue . . . "); 15 Console.ReadKey(true); 16 } 17 }
运行结果:
- 其他实现方案:
1.) 方案1
/// <summary> /// Description of MemberBO. /// </summary> public class SiteSettings { private static SiteSettings instance=null; private static object locker=new object(); private SiteSettings() { } public static SiteSettings Instance { get { if(instance ==null){ Console.WriteLine("Install equals null."); lock(locker){ Console.WriteLine("Enter locker."); Console.WriteLine("new SiteSettings instance."); instance=new SiteSettings(); } } return instance; } } private bool siteClosed=false; public bool SiteClosed { get { return siteClosed; } set { siteClosed = value; } } }
2.) 方案2:
/// <summary> /// Description of MemberBO. /// </summary> public class SiteSettings { private static SiteSettings instance=null; private static object locker=new object(); private SiteSettings() { } public static SiteSettings Instance { get { Console.WriteLine("Install equals null."); lock(locker){ if(instance ==null){ Console.WriteLine("Enter locker."); Console.WriteLine("new SiteSettings instance."); instance=new SiteSettings(); } } return instance; } } private bool siteClosed=false; public bool SiteClosed { get { return siteClosed; } set { siteClosed = value; } } }
3.) 方案3:
/// <summary> /// Description of MemberBO. /// </summary> public class SiteSettings { private static SiteSettings instance=null; private static object locker=new object(); private SiteSettings() { } public static SiteSettings Instance { get { Console.WriteLine("Install equals null."); if(instance ==null){ Console.WriteLine("new SiteSettings instance."); instance=new SiteSettings(); } } return instance; } } private bool siteClosed=false; public bool SiteClosed { get { return siteClosed; } set { siteClosed = value; } } }
4.) 方案4:
/// <summary> /// Description of SiteSettings. /// </summary> public class SiteSettings { private static SiteSettings instance= new SiteSettings(); private SiteSettings() { } public static SiteSettings Instance { get { return instance; } } private bool siteClosed=false; public bool SiteClosed { get { return siteClosed; } set { siteClosed = value; } } }
5.) 方案5:
/// <summary> /// Description of SiteSettings. /// </summary> public class SiteSettings { private static SiteSettings instance=null; private static object locker=new object(); private SiteSettings() { } public static SiteSettings GetInstance() { if(instance==null){ locker(locker){ if(instance==null){ instance=new SiteSettings(); } } } return instance; } private bool siteClosed=false; public bool SiteClosed { get { return siteClosed; } set { siteClosed = value; } } }
- 为什么不推荐方案1,方案2,方案3:
- 方案1,虽然考虑了线程安全,但还不是足够的安全,还没有双重锁定安全
- 方案2,虽然考虑了线程安全,但每次都要进入locker,即使instance对象已经赋值后
- 方案3,线程安全问题就没有考虑。
- 适当的情况下可以选择方案4,方案5
- 方案4,使用“迫切”创建实例(当应用程序启动,初始化系统时,初始化全局变量时创建对象实例),而不用延迟实例化的方法
- 方案5,采用了延迟实例化的方法。
- 注意混淆问题:
不要和Monitor,ReaderWriterLockSlim等这些线程安全的使用方式混淆。
1.) Monitor:提供同步访问对象的机制。
2.) ReaderWriterLockSlim:表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。
- 优缺点:
1.)优点:
a.)确保了系统中保存一个实例对象,为程序带来了开拓思路;
b.)内存开销可能会占用一定空间,但它避免了每次都需要开辟空间的消费;
c.)使得程序能逻辑清理,开发者可以单一的使用该实例对象去操作,而不别每次都要new一个实例对象来进行操作。
2.缺点:
a.)多个用户在操作这个对象时,线程的安全性,就需要考虑。
b.)一直在占用资源,而不可以被回收。
参考资料:《Head First 设计模式》
欢迎拍砖!请牛人们给指点。
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。