1.单例模式

什么是单例模式?(单例模式的实现

属于创建型模式,提供了一种创建对象的方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注:1.单例类只能有一个实例。

  2.单例类必须自己创建自己的唯一实例。

  3.单例类必须给所有其他对象提供这一实例。

 

使用单例的场景:

  1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件、应用配置。

  2.控制资源的情况下,方便资源之间相互通信,如线程池。

 

实现:

  1.私有化该类的构造方法,其他的类或代码无法通过该类的构造方法来实现该类,必须通过调用该类提供的静态方法实例化方法来实例化。

  2.该类提供一个静态的实例化自己的方法,如果该类已经实例化,就直接提供实例化的引用,如果没有实例化,就创建一个实例化引用,并赋予该类保持的引用。

 

实现单例模式的方法

1、单线程单例模式

public sealed class Singleton
{
    public static Singleton instance = null;
    private Singleton() { }
    public static Singleton GetInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
            Console.WriteLine("创建一个单例");
        }
        return instance;
    }
}

缺点:线程不安全,两个线程可能同事检测到 instance==null成立,因为有可能在一瞬间创建两个。其实在多线程运行时,即使已经在内存中创建了实例,但是内存模型并不能保证新的instance能够看见其它线程所创建的实例。因此这种方法不推荐。测试代码如下:打印了两次”创建一个单例“

//创建第一个线程并给予委托
Thread thread1 = new Thread(new ThreadStart(()=>
    {
        Singleton1.GetInstance();
        Console.WriteLine("启动第一个线程");
    }
));
thread1.Start();
//创建第二个线程并给予委托
Thread thread2 = new Thread(new ThreadStart(()=>
    {
        Singleton1.GetInstance();
        Console.WriteLine("启动第二个线程");
    }));
thread2.Start();

2、简单线程安全

public sealed class Singleton2
 {
     private static Singleton2 instance = null;
     private static readonly object padlock = new object();

     private Singleton2() { }
     public static Singleton2 GetInstance()
     {
         lock(padlock)
         {
             if (instance == null)
             {
                 instance = new Singleton2();
                 Console.WriteLine("创建一个单例");
             }
             return instance;
         }
     }
}

 添加了一个object成员以此来实现锁。这种方法是线程安全的,每个线程要创建实例时,都要先去得锁,然后再判断是否为空,也就是保证多线程运行时,只有一个线程能进行进行实例化,而一旦一个线程实例化后,后面的线程取到锁后,就会发现实例已经创建。使用Singleton1中的测试代码,发现只会打印一次"创建一个单例"。

缺点:假设线程足够多,100个吧,每一个线程在进行if(instance==null)判断时,都到等到某一个线程退出后将锁获得。所以会导致性能问题。

3、双层验证下的多线程安全

 public sealed class Singleton2
 {
     private static Singleton2 instance = null;
     private static readonly object padlock = new object();
     private Singleton2() { }
     public static Singleton2 Instance
     {
         get
         {
             if(instance == null)
             {
                 lock (padlock)
                 {
                     if (instance == null)
                         instance = new Singleton2();
                 }
             }
             return instance;
         }
     }
 }

这是对简单线程安全的优化,多进行一次判断,如果instance==null是FALSE,那自然没必要在等待锁再去判断一次。

4、更高效的单例模式——饿汉模式

public sealed class Singleton3
{
    private static readonly Singleton3 instance = new Singleton3();
    static Singleton3() { }
    private Singleton3() { Console.WriteLine("创建一个单例"); }
    public static Singleton3 GetInstance()
    {
        return instance;
    }
}

它是如何保证线程安全的呢?对于每个AppDomain,在C#中类的实例被构造或者静态成员被引用时,静态构造函数才会执行,而且只执行一次。由于这个类在一加载就被实例化,因此,效率上要比前面实现高的多。

为什么叫饿汉?无论我们在程序中用不用,编译器都会实例化一个对象。

5、懒汉模式--使用嵌套类 

public sealed class Singleton
{
    private Singleton(){ }
    public static Singleton GetInstance() 
    { 
        return Nested.instance;
    }
    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested(){ }
        internal static readonly Singleton instance = new Singleton();
    }
}

当嵌套类的静态成员第一次被引用到时,就会触发实例化,因此这是一种懒汉式单例模式。尽管嵌套类可以访问封闭类的私有成员,但情况并非如此,因此这里实例需要是内部的。不过,这不会引起任何其他问题,因为类本身是私有的。

6、net4之后的Lazy泛型

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =new Lazy<Singleton>(() => new Singleton());
    public static Singleton GetInstance() 
    { 
        return lazy.Value;
    }
    private Singleton(){ }
}

上面的代码会隐式的调用LazyThreadSafetyMode.ExecutionAndPublication以实现lazy<Singleton>线程安全模式。

posted @   celestially98  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示