几种常用的单例模式详解

 

Visual Basic .NET Visual C# .NET都属于.NET平台下的语言,它们之间的本质区别较小,区别基本都是语法结构上的,既然两种语言都属于.NET平台,并且最终都是通过MSILCLR机制来运行,要实现它们之间的转换并不难。

 

首先看一下单例的模型

逻辑模型图:

 

物理模型图:

 

单例模式的五种写法。

 

1.简单实现

这种方式创建的对于多线程来讲可能是不安全的,原因是如果某一时刻实例未创建,这时有多个线程在这一时刻同时判断出实例不存在,那么这些线程就会执行后续代码并对实例进行创建,这样必然会导致创建多个实例。

C# Code

public sealed class Singleton 
{ 
    static Singleton instance=null; 
  
    Singleton() 
    { 
    } 
  
    public static Singleton Instance 
    { 
        get
        { 
            if (instance==null) 
            { 
                instance = new Singleton(); 
            } 
            return instance; 
        } 
    } 

}

VB Code

Public NotInheritable Class Singleton 
    Shared m_instance As Singleton = Nothing
  
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            If m_instance Is Nothing Then
                m_instance = New Singleton() 
            End If
            Return m_instance 
        End Get
    End Property
End Class

2.安全的线程

这种方式可以避免简单实现中可能创建多个实例的问题,原因就是由于有Lock或者SyncLock的存在。它的含义就是将一个对象锁定,使访问它的线程在同一时刻只能是一个而不能是多个,其它线程要想访问被锁定的对象,那么必须等到被锁定的对象释放为止。

这种做法是会影响性能的,原因就是不管实例是否创建,每次调用创建方法的时候都需要加锁,而这是没有必要的。

在代码中被锁定的对象是事先创建的也就是先New的,原因就是保证加锁的时候,被锁定的对象已经创建,否则如果该对象未创建就加锁会出错的,这一点请读者用的时候一定注意。

C# Code

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; 
            } 
        } 
    } 
}

VB Code

 

Public NotInheritable Class Singleton 
    Shared m_instance As Singleton = Nothing
    Shared ReadOnly padlock As New Object() 
  
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            SyncLock  padlock 
                If m_instance Is Nothing Then
                    m_instance = New Singleton() 
                End If
                Return m_instance 
            End SyncLock
        End Get
    End Property
End Class

 

3.双重锁定

这种方式的与安全线程的区别就是并不是每次都加锁,而是在加锁之前加了一个判断,即先判断是否创建了实例,如果没有创建实例被那么再加锁。

而为什么会有第二重的判断是否存在实例呢,这也涉及到多线程的问题,具体是因为,当实例没有被创建时,多个线程通过第一层判断,这时只有一个线程锁定对象,并且创建单例对象,注意此时其它的线程并没有退回到第一层的判断之外,而是依然驻留在被锁定对象的外围等待被锁定的对象释放,假如这时被锁定的对象释放了,那么如果没有第二层的判断实例是否存在,则会出现另一个线程创建的第二实例,同理如果其他的线程也通过了第一层的判断,那么第三,第四等多个实例也会被创建,所以存在双层判断是必须的。

C# Code

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; 
        } 
    } 
}

VB Code 

Public NotInheritable Class Singleton 
    Shared m_instance As Singleton = Nothing
    Shared ReadOnly padlock As New Object() 
  
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            If m_instance Is Nothing Then
                SyncLock padlock 
                    If m_instance Is Nothing Then
                        m_instance = New Singleton() 
                    End If
                End SyncLock
            End If
            Return m_instance 
        End Get
    End Property
End Class

4.静态初始化(首选方式)

注意:代码简单是这种创建方式的最大优点。这种方式的创建被称为饿汉式单例类,之所以这样称,是站在CPU占用来讲的,首先从它的创建来看,这种方式创建的单例类是在类被加载的时候就实例化,就像饿汉一样,一点时间都不浪费的疯狂占用CPU。而前面介绍的的单例类的创建被称为懒汉式单例类,这种方式创建的单例类的实例化是要在第一次引用的时候才创建,就像个懒汉一样,能不创建就不创建,能托就托。

通过代码可以明显看出这种方式的实例对象在开始定义的时候是用了New关键字实例化了的,而这点也是饿汉与懒汉的区别。

它的缺点也是因为饿汉对CPU的占用导致出现在引用之前,导致我们对它的实例化很难控制,并不能按照我们想的仅仅在需要的时候实例化。

C# Code

public sealed class Singleton 
{ 
     static readonly Singleton instance=new Singleton(); 
   
     static Singleton() 
     { 
     } 
   
     Singleton() 
    { 
    } 
  
    public static Singleton Instance 
    { 
        get
        { 
            return instance; 
        } 
    } 
}

VB Code

 

Public NotInheritable Class Singleton 
    Shared ReadOnly m_instance As New Singleton() 
  
    Shared Sub New() 
    End Sub
  
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            Return m_instance 
        End Get
    End Property
End Class

5.延迟初始化(比较常用)

这点好处就是在代码简化的同时,将单例的实例化延迟到第一次引用,这样相对静态初始化来说,则明显要高明很多。

C# Code

public sealed class Singleton 
 { 
     Singleton() 
     { 
     } 
   
     public static Singleton Instance 
     { 
         get
        { 
            return Nested.instance; 
        } 
    } 
      
    class Nested 
    { 
        static Nested() 
        { 
        } 
  
        internal static readonly Singleton instance = new Singleton(); 
    } 
}

VB Code

Public NotInheritable Class Singleton 
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            Return Nested.instance 
        End Get
    End Property
  
    Private Class Nested 
        Shared Sub New() 
        End Sub
  
        Friend Shared ReadOnly instance As New Singleton() 
    End Class
End Class

注意:
1、单例模式用的时候并不像我们平时用的那样,直接New一下就可以了,它需要根据具体的情况通过单例类的方法来创建。
2、单例类并没有改进单例类的创建,仅仅是将类限制在类内部而已。
3、以上单例类并没有考虑对象的销毁和垃圾的回收,当然对于.Net的自动垃圾回收和对象销毁来说,这一点不需考虑,但是对于其他平台开发的情况则需注意。
4、单例的应用,应该注意是众所周知的,否则很容易在用的时候出现思维定式的错误。 
原文地址:https://www.cnblogs.com/zs234/p/3233391.html