关于用于静态变量实现singleton的多线程互斥的一点疑问

本文探讨了C#中实现Singleton模式的线程安全问题,特别是静态变量在多线程环境下的安全性。通过示例代码展示了线程安全的Singleton实现,并解释了.NET框架如何保证类的初始化是串行的,从而确保静态变量的线程安全。文中还提到了无需使用双重检查锁定的Singleton设计模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

都知道singleton模式的线程安全方式有两种,一种是在GetInstance方法定义上加上synchronized的锁. 另一种方式是申明成static类型的变量.
我一直有一个疑问.net如何保证static类型是线程安全(实例化变量的操作时间很长,如何保证线程安全)? 我做了如下实验,的确是线程安全的.

[Form1.cs文件(对话框上仅一个按钮)]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(new ThreadStart(ShowBaseSalary));
            Thread thread2 = new Thread(new ThreadStart(ShowBonusAndSalary));
            thread1.Start();           
            thread2.Start();           
           
        }

        private void ShowBaseSalary()
        {
            MessageBox.Show(Test.GetBaseSalary());
        }

        private void ShowBonusAndSalary()
        {
            MessageBox.Show(Test.GetBonusAndSalary(500));
        }
    }


    class Test
    {
        private static Employee employee = new Employee(29);    //实例化变量的时间可能很长,如何保证线程安全(线程1实例过程中,线程1有可能执行到该代码吗?)??
        private int m = 0;

        public static string GetBaseSalary()
        {
            return employee.GetBaseSalary();
        }

        public static string GetBonusAndSalary(int nBonus)
        {
           return employee.GetBonusAndSalary(nBonus);
        }

     
    
    }

 

 

[Employee.cs]

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication2
{
    class Employee
    {

        private const int SALARYLEVEL = 15;  //工资基数

        private int _baseSalary;
        public Employee(int ages)
        {
          
            Random rnd = new Random();
            int nValue = rnd.Next(100); 
            while (nValue !=26)     //模拟类实例化执行很长时间
            {
                _baseSalary = ages * SALARYLEVEL * nValue / 100;
                nValue = rnd.Next(100);           
                System.Threading.Thread.Sleep(1000);
            }
    

           

        }

        //获取加上奖金的工资
        public string GetBonusAndSalary(int nBonus)
        {
            return Convert.ToString(_baseSalary + nBonus);
        }


        //获取基本工资
        public string GetBaseSalary()
        {
            return _baseSalary.ToString();
        }

 

    }
}

 

 

 

 

 

 

另,C#中不需要用锁的线程安全的Singleton设计模式!

典型的线程安全的Singleton实现是使用double-checked locking的实现,但是在.NET中我们并不需要使用double-checked locking就可以优雅地实现Singleton模式。

这个优美的Singleton实现基础是.NET对运行期初始化的完整定义。它的优美之处是不需要典型的double-checked locking。

当CLR加载class Singleton的时候,因为Singleton没有static variables需要被初始化,所以Singleton的初始化其实什么也没做。而对static class LazyHolder来说,直到它被执行的时候才会被初始化。而static class LazyHolder只有载Singleton.GetInstance()被执行的时候才会执行到。当第一次调用GetInstance()的时候 CLR才会加载和初始化LazyHolder这个class。对于LazyHolder class的初始化就是对static variable Instance的初始化。而Instance的初始化就是执行Singleton的private constructor。因为.NET保证class的initialization是serial的,就是说在加载和初始化的过程中我们不需要自己做同步。因为初始化过程是一个serial的操作,所以对于后面的GetInstance,我们不需要做任何同步,它也会返回一个正确初始化的 Singleton对象。

实现代码:

 

 1       public   class  Singleton
 2      {
 3           private   static   class  LazyHolder
 4          {
 5               public   static   readonly  Singleton Instance  =   new  Singleton();
 6          }
 7 
 8           private  Singleton()
 9          {
10          }
11 
12           public   static  Singleton GetInstance()
13          {
14               return  LazyHolder.Instance;
15          }
16      }

 

 

#24楼 2007-01-17 18:14 | 网魂小兵      

这是Singleton设计模式的第五种实现方法,但是一般人都用
public class Singleton
{
private static readonly Singleton Instance = new Singleton();
static Singleton()
{
}

public static Singleton GetInstance()
{
return Instance;
}
}
这个吧!

 

#29楼 2007-01-18 00:28 | kevinshan[未注册用户]
不知道为什么要搞这么复杂,在C#中这样就可以了啊?

sealed class Singleton
{
private Singleton();
public static readonly Singleton Instance=new Singleton();
}

1,私有实例构造器保证了不会被实例化.
2,sealed保证了不会被继承
3,readonly保证了实例化后的自动不会被修改
4,static 自动保证了线程安全的实例化.
5,没有静态构造函数保证了编译器产生的构造函数是BeforeFieldInit,达到了lazy-load目的.

不过我觉的这种情况下为什么不要static class了?非要用Singleton模式?

  
#52楼 2007-08-27 20:35 | wqf[未注册用户]
需要这么麻烦吗?看代码吧~~~
public class Singleton
{
private static Singleton Instance = null;

private Singleton()
{
}

static Singleton()
{
Instance = new Singleton();
}

public static Singleton GetInstance()
{
return Singleton.Instance;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值