首页 > 其他分享 >线程安全单例设计模式

线程安全单例设计模式

时间:2023-01-19 16:12:18浏览次数:44  
标签:private GuidService static 单例 线程 设计模式 guidService

一、什么是单例设计模式中的线程安全?

首先,创建一个单例类:

public sealed class GuidService
{
    private static int counter = 0;
    private static GuidService? _guidService = null;
    public static GuidService GetGuidService
    {
        get
        {
            if (_guidService is null)
                _guidService = new GuidService();
            return _guidService;
        }
    }

    private GuidService()
    {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
}

在主方法中修改调用方式,改为多线程环境,如下:

Parallel.Invoke(() =>
{
    GuidService guidService1 = GuidService.GetGuidService;
    guidService1.PrintDetails("guidService1");
},
() =>
{
    GuidService guidService2 = GuidService.GetGuidService;
    guidService2.PrintDetails("guidService2");
});
Console.ReadKey();

执行结果如下:

Counter Value 2
Counter Value 2
guidService1
guidService2

采用Parallel.Invoke()并行方法调用GetGuidService属性,因为我们在这里编写代码的方式是允许两个不同的线程可以同时计算条件 if (instance == null) ,并且两个线程都发现条件为真,它们都会创建实例,这违反了单例设计模式。

二、单例模式中的懒加载是什么?

在上边代码示例中,只有调用类的GetGuidService属性时,对象才会被创建,单例实例的延迟创建,就是懒加载,也就是惰性初始模式。这种方式在单线程环境中工作的很好,但是在多线程环境中,多个线程同时调用 GetGuidService 属性时,惰性初始模式最终可能会创建单例类的多个实例。

三、如何实现线程安全的单例设计模式?

可以使用C#中的Lock来控制多线程环境中的多个线程同时访问的情况,当然,还有其它方式,但是,锁是处理单例实例的最佳选项。

四、使用锁来实现线程安全的单例设计模式

使用锁,可以同步该方法。在任何给定的时间点只有一个线程可以访问它。在下面的代码中使用锁来锁定共享资源,当线程访问时,会先判断该共享资源是否已被锁定,如果条件成立,就表明内部已有线程访问,就无法进入内部执行创建实例代码,然后检查是否创建了实例。如果实例已经创建,那么只需返回该实例,否则创建该实例,然后返回该实例。代码如下:

public sealed class GuidService
{
    private static int counter = 0;
    private static GuidService? _guidService = null;
    private static readonly object Instancelock = new object();
    public static GuidService GetGuidService
    {
        get
        {
            lock (Instancelock)
            {
                if (_guidService is null)
                    _guidService = new GuidService();
                return _guidService;
            }
        }
    }

    private GuidService()
    {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
}

输出结果:

Counter Value 1
guidService1
guidService2

上面的代码实现使用锁解决了多线程问题。但问题是它会降低应用程序的速度,因为在任何给定的时间点,只有一个线程可以访问 GetInstance 属性,这样就会造成一些问题,比如,第一个线程已经创建对象成功,但是还未释放被锁对象,此时不管多少个线程访问,就会进入阻塞状态,而不会获取到被创建的对象。可以利用双重检查锁定模式机制解决上述问题,代码如下:

public sealed class GuidService
{
    private static int counter = 0;
    private static GuidService? _guidService = null;
    private static readonly object Instancelock = new object();
    public static GuidService GetGuidService
    {
        get
        {
            if (_guidService is null)
            {
                lock (Instancelock)
                {
                    if (_guidService is null)
                        _guidService = new GuidService();
                }
            }
            return _guidService;
        }
    }

    private GuidService()
    {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
}

在双重检查锁定模式机制中,当创建了一个实例之后,再次调用GetGuidService属性就不必要进入同步代码块,不用竞争锁。直接返回前面创建的实例即可。

标签:private,GuidService,static,单例,线程,设计模式,guidService
From: https://www.cnblogs.com/dcy521/p/17061679.html

相关文章

  • 谷歌浏览器启用多线程下载
    谷歌浏览器启用多线程下载功能教程1、双击进入软件,在页面上方地址栏中输入“chrome://flags/#enable-parallel-downloading”并回车访问   2、进入新界......
  • 设计模式23模式介绍
    摘自:https://blog.csdn.net/guorui_java/article/details/104026988目录一、什么是设计模式二、设计模式的三大分类及关键点1、创建型模式2、结构型模式3、行为型模......
  • 【并发编程】线程间的通信
    文章目录​​1.wait、notify、notifyAll​​​​2.生产者消费者模型​​​​3.管道流进行线程间的通信​​​​4.Thread.join()方法​​​​5.Condition详解​​1.wait、not......
  • 线程池处理爬虫电影票房排行榜
    需求:爬取1996-2023年电影票房排行榜首先,我们先爬取一年的数据,然后通过循环,逐一爬取每一年的数据。通过测试,话费时间32秒,代码如下:importrequestsfromlxmlimportetr......
  • 单例模式类为什么需要用sealed关键字修饰?
    使用单例设计模式,需要确保在任何给定的时间点对于整个应用程序只有一个特定类的实例可用。使用私有构造函数,可以避免类在外部被实例化,但是却无法避免内部类(嵌套类)的继承,如......
  • 设计模式
    设计模式目录设计模式设计原则创建模式单例模式Singleton1.饿汉式2.懒汉式3.静态内部类方法4.枚举单例工厂模式Factory简单工厂模式工厂方法模式抽象工厂模式构造者......
  • 【并发编程】线程安全性问题
    文章目录1.什么是线程安全性2.原子性操作3.深入理解synchronized3.4.volatile关键字3.5.happens-before规则3.6.如何避免线程安全性问题1.什么是线程安全性当......
  • 【并发编程】线程的基础知识篇
    文章目录1.进程与线程的区别2.线程的状态相互转换3.创建线程的方式4.线程的挂起和恢复5.线程的中断操作6.线程的优先级7.守护线程1.进程与线程的区别(1)什么是......
  • jmeter添加全局变量,跨线程组传递参数
    在软件测试中,当我们想把某个变量值想设置为全局变量,也就是在任何一个线程组都可以使用该变量时,我们就要用到BeanShell取样器,示例如下:1.拿到某个接口的变量值2.通过BeanSh......
  • 设计模式之模板方法模式和策略模式
    今天看了雷神的公开课,再次学习了设计模式的五个原则以及两个设计模式的应用案例模板方法模式:定义一个算法骨架(一套业务流程),子类可以实现里面的一个或多个步骤eg:对于Spr......