码迷,mamicode.com
首页 > 其他好文 > 详细

单例模式

时间:2016-09-17 08:20:50      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

什么是单例模式?

      简单来说就是要创建一个独一无二的对象

      确保一个类只有一个实例,并提供一个全局的访问点。

有哪些使用场景?

  •  线程池
  •  缓存
  •  注册表
  •  充当打印机、显卡等设备的驱动程序的对象

 剖析经典的单件模式的实现 

技术分享
 1 public class Singleton
 2 {
 3         private static Singleton singleton;
 4         private Singleton()
 5         {       
 6         }
 7         public static Singleton GetInstance()
 8         {
 9             if (null == singleton)
10             {
11                 singleton = new Singleton ();
12             }
13             return singleton;
14         }
15  }
View Code

 

1.利用静态变量来记录唯一的实例
2.把构造器声明为私有的,只有singleton类内部才可以调用构造器
3.用getInstance()实例化对象,并返回这个实例。
4.null==singleton是空的表示没有创建实例,如果它不存在我们就可以利用私有构造器产生一个singleton的实例并把它赋值到静态变量中。请注意如果我们不需要这个实例,他就永远不会产生。这就是“延迟实例化”
5.如果不是null,就说明已经有了实例,我们直接跳到return语句。

 

 单件模式的类图

 

技术分享

 单件模式的序列图

 

 

 

技术分享

 Client调用

技术分享
 1  public class Client
 2     {
 3         static void Main(string[] args)
 4         {
 5             Singleton s1 = Singleton .GetInstance();
 6 
 7             Singleton s2 = Singleton .GetInstance();
 8 
 9             Console.WriteLine(s1 == s2);
10 
11             Console.ReadKey();
12         }
13     }
View Code

 输出结果: True

 技术分享

client调用结果分析
1.从上面的结果可以看出尽管两次访问了GetInstance(),但是访问的只是同一个实例。
2.由于构造函数设为私有的,类外部无法使用new实例化一个实例,只能通过getInstance()创建一个实例,如果存在则不会创建实例,而是调用以前生成的实例。

 

分析经典单例模式存在的问题

如果多个线程同时调用呢?我们举个例子,例如有线程A和B两个线程,A线程进入if判断语句后还没实例化,B线程到达,此时singleton还是为null,这样的话就让两个线程均通过if语句判断,然后调用new singleton()了,这样就创建了两个实例,很显然就违反了单例模式的初衷了。

 

如何解决多线程的问题?

方法一:双重检查锁定

技术分享
 1 public class Singleton 
 2     { 
 3         private static Singleton singleton;
 4         private static readonly object syncObject = new object();
 5        private Singleton()  { }
 6         public static Singleton GetInstance() 
 7         { 
 8             if (singleton == null) 
 9             { 
10                 lock (syncObject) 
11                 {     
12                     if (singleton == null) 
13                     { 
14                         singleton = new Singleton(); 
15                     } 
16                 } 
17             } 
18             return singleton; 
19         } 
20     } 
View Code

 

1、例如有两个线程A和B,当线程A到达lock下面的if语句时,线程B也到到达lock语句,此时线程B不会往下执行,因为已经锁定,需要等线程B执行完lock语句块,才能往下走。

2、可以看到上面的代码有两个if(singleton==null),第一个其实是基于性能的考虑,如果没有第一个if(single==null),那每次调用这段代码时,当有多个线程时都会造成线程阻塞。而加了以后,如果已经创建了对象,当调用到第一个if(single==null)时,就会跳到return语句,不会执行lock代码。保证了性能最优。

3、第二个if(singleton==null)保证了多线程的环境下只创建一个对象。

其中需要注意lock的用法

1.lock关键字的参数必须为引用类型,如果是值类型,会报编译错误。
2.锁定的类型必须是安全的,所以是private的,如果是public的话可能其他地方也会锁定它,可能会导致死锁。

方法二:饿汉式单例

技术分享
 1 namespace Singleton {  
 2        public  class Singleton  
 3        { 
 4            private static readonly Singleton singleton = new Singleton();
 5            private Singleton()  {  }
 6            public static Singleton GetInstance() 
 7            {  
 8                return singleton; 
 9             } 
10         } 
11     }
View Code

 

1、当程序一启动时就创建了一个对象,并用静态变量来接收它。

2、当调用GetInstance()方法时直接返回静态变量。

3、在整个程序中只有一次创建对象,就是程序启动时。所以在多线程使用中不会产生问题。

4、在程序一启动时就已经创建了对象,也就提前占用了资源,当对提前占用资源不关心的话,可以使用此方法。

 

总结:

  • 单例模式使类在程序生命周期的任何时刻都只有一个实例
  • 单例的构造函数是私有的
  • 必须通过 GetInstance()来请求得到这个单例类的实例。

 

单例模式

标签:

原文地址:http://www.cnblogs.com/danielhappy/p/5877266.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!