欢迎光临
我们一直在努力

C# 多线程安全单例模式

一、实验目的

  • 理解单例模式核心:保证程序全局有且仅有一个类实例对象

  • 掌握线程锁lock作用:解决多线程并发,重复创建单例漏洞

  • 实现跨窗体、跨类调用同一个对象,共享成员变量数据

  • 区分两种单例调用方式:静态方法调用、静态字段直接调用

  • 二、项目文件结构

    一共4个代码文件,全部隶属于命名空间:_3单例类

  • Singleton.cs:单例核心类(加线程锁、私有构造函数)

  • Form1.cs:WinForm窗体、按钮触发事件

  • Class1.cs:外部测试类1,调用单例

  • Class2.cs:外部测试类2,调用单例


  • 三、代码分段精细化整理(保留全部原生注释)

    3.1 核心类:Singleton.cs【单例主体】

    功能:编写线程安全单例,定义血量、扣血方法,全局唯一对象

    namespace _3单例类
    {
    internal class Singleton
    {
    //===================== 单例全局字段 =====================
    //单例:保证整个项目中有且仅有一个对象
    //对外开放一个公共的属性访问点
    //获取单例对象,静态字段全局共享
    public static Singleton instance = null;

    static object locker = new object(); // 线程锁标志

    //===================== 私有构造函数 =====================
    //防止在外部new 创建对象,把构造函数改成私有的
    //封堵外部实例化通道,是实现单例必要条件
    private Singleton()
    {
    }

    //===================== 对外获取单例方法 =====================
    //对外提供一个方法的访问点
    //获取单例对象
    public static Singleton GetSingle()
    {
    // 互斥锁
    //线程锁:防止多个线程在同一时间访问这个单例对象
    //如果多个线程同时访问,需要排队执行,防止并发创建多个对象
    lock (locker)
    {
    // 如果对象为空了, 再去创建对象
    // 如果对象不为空,直接复用已有对象,不再new
    if (instance == null)
    {
    instance = new Singleton();
    }
    }
    return instance;
    }

    //===================== 业务测试成员 =====================
    public int HP = 100;//验证单例对象只有一个:全局共享血量
    /// <summary>
    /// 扣血方法:每次调用血量减10
    /// </summary>
    /// <returns>扣减之后的血量</returns>
    public int SubHP()
    {
    return HP -= 10;
    }
    }
    }

    3.2 窗体代码:Form1.cs【交互页面】

    功能:四个按钮,分别两种方式调用单例、两个外部类调用单例

    namespace _3单例类
    {
    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    //按钮1:实例化Class1,内部调用单例扣血
    private void button1_Click(object sender, EventArgs e)
    {
    Class1 c = new Class1();
    label1.Text = c.Attack();
    }

    //按钮2:实例化Class2,内部调用单例扣血
    private void button2_Click(object sender, EventArgs e)
    {
    Class2 c = new Class2();
    label1.Text = c.Attack();
    }

    //按钮3:通过【静态方法】获取单例对象,执行扣血
    private void button3_Click(object sender, EventArgs e)
    {
    label1.Text = Singleton.GetSingle().SubHP().ToString();
    }

    //按钮4:直接通过【静态字段】获取单例对象,执行扣血
    private void button4_Click(object sender, EventArgs e)
    {
    label1.Text = Singleton.instance.SubHP().ToString();
    }
    }
    }

    3.3 测试类一:Class1.cs

    功能:新建独立类,跨类调用全局单例,验证数据共享

    namespace _3单例类
    {
    internal class Class1
    {
    public string Attack() //定义一个攻击的方法
    {
    // 调用单例的SubHP方法:属于非静态方法
    // 非静态方法不能直接调用,必须获取单例对象调用
    // 获取全局唯一单例对象
    return Singleton.GetSingle().SubHP().ToString();
    }
    }
    }

    3.4 测试类二:Class2.cs

    功能:和Class1相互独立,依旧调用同一个单例对象

    namespace _3单例类
    {
    internal class Class2
    {
    public string Attack() //定义一个攻击的方法
    {
    // 调用单例的SubHP方法 方法非静态的方法 ,找对象去调用
    // 获取单例对象
    return Singleton.GetSingle().SubHP().ToString();
    }
    }
    }

    四、关键知识点精细注释(考试+作业背诵)

    4.1 单例模式三大硬性条件

    • 私有构造函数:禁止外部使用new,杜绝随意创建对象

    • 静态全局实例:static修饰对象,全局唯一常驻内存

    • 对外开放访问入口:静态方法/静态字段,提供唯一访问通道

    4.2 lock线程锁作用

    不加lock:多线程同时执行,会同时判断instance==null,同时new对象,生成多个实例,单例失效

    添加lock:线程排队执行,同一时刻只允许一个线程进入代码块,保证只会创建一次对象

    4.3 两种调用单例方式区别

    • 方式1:Singleton.GetSingle():调用静态方法获取,安全规范,课堂推荐写法

    • 方式2:Singleton.instance:直接读取公共静态字段,写法简便,封装性弱

    4.4 实验验证原理

    初始HP = 100,无论点击四个任意按钮、无论Class1/Class2哪个类调用,血量持续递减: 证明:全程序共用同一个Singleton对象,单例模式生效


    五、运行结果

    依次点击按钮,label1显示数值依次:90→80→70→60…… 跨窗体、跨类修改HP值,全局同步变化,不存在独立血量,验证单例成功。

    赞(0)
    未经允许不得转载:171主机测评 » C# 多线程安全单例模式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址