C# 单例模式和窗体的单例打开方法
第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我……
public class Singleton
{
    private static Singleton _instance = null;
    private Singleton(){}
    public static Singleton CreateInstance()
    {
        if(_instance == null)
{
            _instance = new Singleton();
        }
        return _instance;
    }
}
第二种考虑了线程安全,不过有点烦,但绝对是正规写法,经典的一叉
public class Singleton
{
    private volatile static Singleton _instance = null;
    private static readonly object lockHelper = new object();
    private Singleton(){}
    public static Singleton CreateInstance()
    {
        if(_instance == null)
        {
            lock(lockHelper)
            {
                if(_instance == null)
                     _instance = new Singleton();
            }
        }
        return _instance;
    }
}
第三种可能是C#这样的高级语言特有的,实在懒得出奇
public class Singleton
{
private Singleton(){}
    public static readonly Singleton instance = new Singleton();
}
一、 单例(Singleton)模式
单例模式的特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其它对象提供这一实例。
单例模式应用:
- 每台计算机可以有若干个打印机,但只能有一个Printer Spooler,避免两个打印作业同时输出到打印机。
- 一个具有自动编号主键的表可以有多个用户同时使用,但数据库中只能有一个地方分配下一个主键编号。否则会出现主键重复。
二、 Singleton模式的结构:

Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,确保用户无法通过new直接实例它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance方法负责检验并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。(关于线程问题以及C#所特有的Singleton将在后面详细论述)。
三、 程序举例:
该程序演示了Singleton的结构,本身不具有任何实际价值。
 // Singleton pattern -- Structural example
// Singleton pattern -- Structural example   using System;
using System;
 // "Singleton"
// "Singleton" class Singleton
class Singleton {
{ // Fields
  // Fields private static Singleton instance;
  private static Singleton instance;
 // Constructor
  // Constructor protected Singleton() {}
  protected Singleton() {}
 // Methods
  // Methods public static Singleton Instance()
  public static Singleton Instance() {
  { // Uses "Lazy initialization"
    // Uses "Lazy initialization" if( instance == null )
    if( instance == null ) instance = new Singleton();
      instance = new Singleton();
 return instance;
    return instance; }
  } }
}
 /// <summary>
/// <summary> /// Client test
/// Client test /// </summary>
/// </summary> public class Client
public class Client {
{ public static void Main()
  public static void Main() {
  { // Constructor is protected -- cannot use new
    // Constructor is protected -- cannot use new Singleton s1 = Singleton.Instance();
    Singleton s1 = Singleton.Instance(); Singleton s2 = Singleton.Instance();
    Singleton s2 = Singleton.Instance();
 if( s1 == s2 )
    if( s1 == s2 ) Console.WriteLine( "The same instance" );
      Console.WriteLine( "The same instance" ); }
  } }
}四、 在什么情形下使用单例模式:
使用Singleton模式有一个必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式。反过来,如果一个类可以有几个实例共存,就不要使用单例模式。
注意:
不要使用单例模式存取全局变量。这违背了单例模式的用意,最好放到对应类的静态成员中。
不要将数据库连接做成单例,因为一个系统可能会与数据库有多个连接,并且在有连接池的情况下,应当尽可能及时释放连接。Singleton模式由于使用静态成员存储类实例,所以可能会造成资源无法及时释放,带来问题。
五、 Singleton模式在实际系统中的实现
下面这段Singleton代码演示了负载均衡对象。在负载均衡模型中,有多台服务器可提供服务,任务分配器随机挑选一台服务器提供服务,以确保任务均衡(实际情况比这个复杂的多)。这里,任务分配实例只能有一个,负责挑选服务器并分配任务。
 // Singleton pattern -- Real World example
// Singleton pattern -- Real World example  
 using System;
using System; using System.Collections;
using System.Collections; using System.Threading;
using System.Threading;
 // "Singleton"
// "Singleton" class LoadBalancer
class LoadBalancer {
{ // Fields
  // Fields private static LoadBalancer balancer;
  private static LoadBalancer balancer; private ArrayList servers = new ArrayList();
  private ArrayList servers = new ArrayList(); private Random random = new Random();
  private Random random = new Random();
 // Constructors (protected)
  // Constructors (protected) protected LoadBalancer()
  protected LoadBalancer() {
  { // List of available servers
    // List of available servers servers.Add( "ServerI" );
    servers.Add( "ServerI" ); servers.Add( "ServerII" );
    servers.Add( "ServerII" ); servers.Add( "ServerIII" );
    servers.Add( "ServerIII" ); servers.Add( "ServerIV" );
    servers.Add( "ServerIV" ); servers.Add( "ServerV" );
    servers.Add( "ServerV" ); }
  }
 // Methods
  // Methods public static LoadBalancer GetLoadBalancer()
  public static LoadBalancer GetLoadBalancer() {
  { // Support multithreaded applications through
    // Support multithreaded applications through // "Double checked locking" pattern which avoids
    // "Double checked locking" pattern which avoids // locking every time the method is invoked
    // locking every time the method is invoked if( balancer == null )
    if( balancer == null ) {
    { // Only one thread can obtain a mutex
      // Only one thread can obtain a mutex Mutex mutex = new Mutex();
      Mutex mutex = new Mutex(); mutex.WaitOne();
      mutex.WaitOne();
 if( balancer == null )
      if( balancer == null ) balancer = new LoadBalancer();
        balancer = new LoadBalancer();
 mutex.Close();
      mutex.Close(); }
    } return balancer;
    return balancer; }
  }
 // Properties
  // Properties public string Server
  public string Server {
  { get
    get {
    { // Simple, but effective random load balancer
      // Simple, but effective random load balancer int r = random.Next( servers.Count );
      int r = random.Next( servers.Count ); return servers[ r ].ToString();
      return servers[ r ].ToString(); }
    } }
  } }
}
 /// <summary>
/// <summary> /// SingletonApp test
/// SingletonApp test /// </summary>
/// </summary> ///
/// public class SingletonApp
public class SingletonApp {
{ public static void Main( string[] args )
  public static void Main( string[] args ) {
  { LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b1 = LoadBalancer.GetLoadBalancer(); LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b2 = LoadBalancer.GetLoadBalancer(); LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b3 = LoadBalancer.GetLoadBalancer(); LoadBalancer b4 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b4 = LoadBalancer.GetLoadBalancer();
 // Same instance?
    // Same instance? if( (b1 == b2) && (b2 == b3) && (b3 == b4) )
    if( (b1 == b2) && (b2 == b3) && (b3 == b4) ) Console.WriteLine( "Same instance" );
      Console.WriteLine( "Same instance" );
 // Do the load balancing
    // Do the load balancing Console.WriteLine( b1.Server );
    Console.WriteLine( b1.Server ); Console.WriteLine( b2.Server );
    Console.WriteLine( b2.Server ); Console.WriteLine( b3.Server );
    Console.WriteLine( b3.Server ); Console.WriteLine( b4.Server );
    Console.WriteLine( b4.Server ); }
  } }
}六、 C#中的Singleton模式
C#的独特语言特性决定了C#拥有实现Singleton模式的独特方法。这里不再赘述原因,给出几个结果:
方法一:
下面是利用.NET Framework平台优势实现Singleton模式的代码:
 sealed class Singleton
sealed class Singleton {
{ private Singleton();
   private Singleton(); public static readonly Singleton Instance=new Singleton();
   public static readonly Singleton Instance=new Singleton(); }
}这使得代码减少了许多,同时也解决了线程问题带来的性能上损失。那么它又是怎样工作的呢?
注意到,Singleton类被声明为sealed,以此保证它自己不会被继承,其次没有了Instance的方法,将原来_instance成员变量变成public readonly,并在声明时被初始化。通过这些改变,我们确实得到了Singleton的模式,原因是在JIT的处理过程中,如果类中的static属性被任何方法使用时,.NET Framework将对这个属性进行初始化,于是在初始化Instance属性的同时Singleton类实例得以创建和装载。而私有的构造函数和readonly(只读)保证了Singleton不会被再次实例化,这正是Singleton设计模式的意图。
(摘自:http://www.cnblogs.com/huqingyu/archive/2004/07/09/22721.aspx )
不过这也带来了一些问题,比如无法继承,实例在程序一运行就被初始化,无法实现延迟初始化等。
详细情况可以参考微软MSDN文章:《Exploring the Singleton Design Pattern》
方法二:
既然方法一存在问题,我们还有其它办法。
 public sealed class Singleton
public sealed class Singleton {
{ Singleton()
  Singleton() {
  { }
  }
 public static Singleton GetInstance()
  public static Singleton GetInstance() {
  { return Nested.instance;
    return Nested.instance; }
  } 
     class Nested
  class Nested {
  { // Explicit static constructor to tell C# compiler
    // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit
    // not to mark type as beforefieldinit static Nested()
    static Nested() {
    { }
    }
 internal static readonly Singleton instance = new Singleton();
    internal static readonly Singleton instance = new Singleton(); }
  } }
}这实现了延迟初始化,并具有很多优势,当然也存在一些缺点。详细内容请访问:《Implementing the Singleton Pattern in C#》。文章包含五种Singleton实现,就模式、线程、效率、延迟初始化等很多方面进行了详细论述。
参考链接:http://blog.csdn.net/zhuangzhineng/article/details/3927455
单 例模式是广为流传的设计模式中的一种。本质上,单例模式是一个只允许创建一个实例,并提供对这个实例简单的访问途径的类。一般而言,单例模式在创建实例时 不允许传递任何参数-否则不同参数导致不同的实例创建,就会出现问题!(如果同一个实例可以被同参的不同请求所访问,那么工厂模式会更适合。)这篇文章只 针对无参创建的请求进行讨论。典型的,单例模式的应用往往是延后创建的(created lazily)---只有在第一次被用到的时候才会被创建。在C#中有实现单例模式有很多种方法。我将在这里一一展现给大家,从最常见的、线程不安全的到 延后创建的、线程安全的、再到简洁高效的版本。注意在下面的代码中,我忽略了所有私有域,因为私有域是默认的类的成员。In many other languages such as Java, there is a different default, and private should be used.
所有的这些实现都有以下四个特征:
    1.只有一个构造函数,而且是私有的,不带参数的。这是为了防止其他类对其实例化(这和模式本身有冲突)。同时也防止了子类化--如果一个单例能被子类化 一次,就能被子类化两次,而如果每个子类可以创建一个实例,这与模式本身又产生了冲突。如果你(遇到这样的情况):只有在运行期才能知道实际的类型,因此 你需要一个父类的单例,你可以使用工厂模式。
  2.类是密封的。这并不是必须的,严格的说,即如上一点所说的原因,可以提高JIT(Just-In-Time , 运行时编译执行的技术)的效率。
    3.一个静态变量用来保存单例的引用。
    4.一个用以访问单例引用的公用静态方法。
注意:所有这些实现都用到一个公用静态属性Instance,作为访问实例的方法。当然都可以替换为方法,这对线程安全和性能都没有影响。
版本1-非线程安全
// Bad code! Do not use!
public sealed class Singleton
{
    static Singleton instance=null;
    Singleton()
     {
    }
    public static Singleton Instance
     {
        get
         {
            if (instance==null)
             {
                instance = new Singleton();
            }
            return instance;
        }
    }
}
 
如 上提示,上面的代码是非线程安全的。两个线程可能同时判断“if (instance==null)”,发现为TRUE,于是都创建了实例,这又违背了单例模式。注意:事实上在表达式反应前实例已经被创建了,内存模型并 不保证新的实例的值被其他的线程看到,除非对应的内存屏障已经通过了。(CPU越过内存屏障后,将刷新自已对存储器的缓冲状态,这样其他线程才能同步自己 的copy)
版本2 - 简单的线程安全
public sealed class Singleton
{
    static Singleton instance=null;
    static readonly object padlock = new object();
    Singleton()
     {
    }
    public static Singleton Instance
     {
        get
         {
            lock (padlock)
             {
                if (instance==null)
                 {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
}
这 个实现是线程安全的。线程首先对共用的对象进行锁定,然后判断实例是否在之前已经创建。这里要小心内存屏障问题(在锁定的时候确保所有的读操作发生在所获 得之后,在解锁的时候确保所有的写操作发生在锁释放之前),确保只有一个线程创建了实例(因为在同一时刻只有一个线程可以在执行那段代码--到了第二个线 程进入的时候,第一个线程已经完成了实例的创建,这样表达式返回false)。不幸的是,由于在每次访问的时候都要进行锁定,所以影响了性能。(这对于多 线程并发的高性能要求的应用显得尤为重要)。注意有些该版本的实现对typeof(Singleton)进行锁定,但我是对类的私有静态变量进行锁定。对 那些可被其他类访问的对象进行锁定或对类型进行锁定会导致性能问题甚至引起死锁。这是一个地雷-任何地方都有可能发生,只有对本就为锁定而创建的对象进行 锁定或是那些因为某些目的而被锁定的文档才是安全的。通常这些对象都是私有的。这样有助于写出线程安全的程序。
版本3 -- 用双重检测机制的线程安全
// Bad code! Do not use!
public sealed class Singleton
{
    static Singleton instance=null;
    static readonly object padlock = new object();
    Singleton()
     {
    }
    public static Singleton Instance
     {
        get
         {
            if (instance==null)
             {
                lock (padlock)
                 {
                    if (instance==null)
                     {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
}
C#单例模式的几种实现方式
文章总结自张波老师的视频教程
单例模式
- 动机(Motivation) - 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
- 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
- 这应该是类设计者的责任,而不是使用者的责任
 
- 意图(Intent) - 保证一个类仅有一个实例,并提供一个该实例的全局访问点。——《设计模式》GoF
 
简单实现
public sealed class Singleton
{
    private static Singleton _instance = null;
    private Singleton()
    {
    }
    public static Singleton Instance
    {
        get { return _instance ?? (_instance = new Singleton()); }
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
说明:
- 对于线程来说不安全
- 单线程中已满足要求
- 优点: 
- 由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能
- 直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的 singleton。
 
线程安全的
public sealed class Singleton
{
    private static Singleton _instance = null;
    private static readonly object Padlock = new object();
    private Singleton()
    {
    }
    public static Singleton Instance
    {
        get
        {
            lock (Padlock)
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
            }
            return _instance;
        }
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
说明:
- 同一个时刻加了锁的那部分程序只有一个线程可以进入
- 对象实例由最先进入的那个线程创建
- 后来的线程在进入时(instence == null)为假,不会再去创建对象实例
- 增加了额外的开销,损失了性能
双重锁定
public sealed class Singleton
{
    private static Singleton _instance = null;
    private static readonly object Padlock = new object();
    private Singleton()
    {
    }
    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (Padlock)
                {
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                    }
                }
            }
            return _instance;
        }
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
说明:
- 多线程安全
- 线程不是每次都加锁
- 允许实例化延迟到第一次访问对象时发生
静态初始化
public sealed class Singleton
{
    private static readonly Singleton _instance = null;
    static Singleton()
    {
        _instance = new Singleton();
    }
    private Singleton()
    {
    }
    public static Singleton Instance
    {
        get
        {
            return _instance;
        }
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
说明:
- 依赖公共语言运行库负责处理变量初始化
- 公共静态属性为访问实例提供了一个全局访问点
- 对实例化机制的控制权较少(.NET代为实现)
- 静态初始化是在 .NET 中实现 Singleton 的首选方法
延迟初始化
public sealed class Singleton
{
    private Singleton()
    {
    }
    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }
    private class Nested
    {
        internal static readonly Singleton instance = null;
        static Nested()
        {
            instance = new Singleton();
        }
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
说明:
- 初始化工作由Nested类的一个静态成员来完成,这样就实现了延迟初始化
注意事项
- Singleton模式中的实例构造器可以设置为protected以允许子类派生。
- Singleton模式一般不要支持ICloneable接口,因为这可能会导致多个对象实例,与Singleton模式的初衷违背。
- Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。
- Singletom模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来讲,我们一般没有必要对其销 毁进行特殊的管理。
总结
- Singleton模式是限制而不是改进类的创建。
- 理解和扩展Singleton模式的核心是“如何控制用户使用new对一个类的构造器的任意调用”。
- 可以很简单的修改一个Singleton,使它有少数几个实例,这样做是允许的而且是有意义的。
C# 单例模式和窗体的单例打开方法的更多相关文章
- 0606-工厂模式、单例模式、DBDA的单例和完整功能
		工厂模式:只要指定类名,就可以据此获取一个该类的对象. 单例模式:某个类,只允许其“创建”出一个对象. 单例的方法:三私一公(一个私有化对象,一个私有化构造方法,一个私有化克隆方法,一个公共方法返回对 ... 
- DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法
		原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ... 
- 【Java】单例设计模式
		文章目录 单例设计模式 什么是设计模式 单例设计模式 实现 饿汉式 懒汉式 饿汉式与懒汉式的区别 饿汉式 懒汉式 单例模式的应用场景 单例设计模式 什么是设计模式 设计模式是在大量的实践中总结和理论化 ... 
- 关于UIApplication单例传值
		由于UIApplication的是一个系统级别的单例,那么就能够省去自己创建单例的方法,将需要需要的类对象,在UIApplication单例内声明一个,通过点语法来实现单个 需要调用的实现单例模式的类 ... 
- java单例之enum实现方式
		传统的两私有一公开(私有构造方法.私有静态实例(懒实例化/直接实例化).公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例), 目前最为安全的实现单例的方法是通过内部静态en ... 
- iOS设计模式 - 单例
		备注:只能通过类的类方法才能创建单例类的实例,[[类名 alloc]init]创建实例没有用的. 原理图 说明 1. 单例模式人人用过,严格的单例模式很少有人用过 2. 严格的单例模式指的是无法通过常 ... 
- iOS 设计模式之单例
		设计模式:单例 一. 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并 ... 
- Java开发之单例设计模式
		设计模式之单例模式: 一.单例模式实现特点:①单例类在整个应用程序中只能有一个实例(通过私有无参构造器实现):②单例类必须自己创建这个实例并且可供其他对象访问(通过静态公开的访问权限修饰的getIns ... 
- JS单例设计模式
		单例,指的是只有一个实例的对象. 在应用单例模式时,生成单例的类必须保证只有一个实例的存在,很多时候整个系统只需要拥有一个全局对象,才有利于协调系统整体的行为.比如在整个系统的配置文件中,配置 ... 
随机推荐
- python黑帽子-黑客与渗透测试编程之道(源代码)
			链接: https://pan.baidu.com/s/1i5BnB5V 密码: ak9t 
- JS图片验证码
			!(function(window, document) { var size = 5;//设置验证码长度 function GVerify(options) { //创建一个图形验证码对象,接收op ... 
- 【repost】jQuery笔记总结
			第一节 jQuery初步认知 jQuery概述 JQuery概念 javascript概念 基于Js语言的API和语法组织逻辑,通过内置window和document对象,来操作内存中的DOM元素 J ... 
- uniDBGrid实行多选表格行
			http://blog.csdn.net/shuiying/article/details/11374655 uniDBGrid本身是支持checkBox多选的,但必须是Boolean的字段才行,只要 ... 
- C++中const关键字 理解
			const:符号常量 使用符号常量写出的代码更容易维护:指针是边读边移动,而不是边写边移动,许多函数参数是只读不写的. const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替 ... 
- WHU1124 Football Match
			http://acm.whu.edu.cn/learn/problem/detail?problem_id=1124 题目大意:有N支球队,你们是第N支.每个队伍已经有一些分数了,接下来还有M场比赛. ... 
- 从零开始的程序逆向之路 第一章——认识OD(Ollydbg)以及常用汇编扫盲
			作者:Crazyman_Army 原文来自:https://bbs.ichunqiu.com/thread-43041-1-1.html 0×00 序言: 1.自从上次笔者调戏完盗取文件密码大黑客后, ... 
- struts2框架学习笔记6:拦截器
			拦截器是Struts2实现功能的核心部分 拦截器的创建: 第一种: package interceptor; import com.opensymphony.xwork2.ActionInvocati ... 
- 分布式控制系统Git学习
			git : n. 饭桶,无用的人 github : n. 社交编程及代码托管网站 hub: n. 中心:毂:木片 Git是一个分布式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创 ... 
- xtrabackup备份mysql-1
			1,在mysql服务器上安装xtrabackup 2,创建备份目录,使用xtrabackup做全备 3,到备份目录查看效果 我这台服务器搭建的是MediaWiki,可以看到wikidb这个库 恢复流程 ... 
