C#Singleton线程安全

use*_*857 10 c# singleton thread-safety

我有一个类似于此的单例类

public class Singleton
{
    private static Singleton m_instance;
    private Timer m_timer;
    private static List<CustomObject> m_cacheObjects;

    private Singleton()
    {    
        m_cacheObjects = new List<CustomObject>();
        m_timer= new Timer(MyTimerCallBack, 
                           null, 
                           TimeSpan.FromSeconds(60), 
                           TimeSpan.FromSeconds(60));           
    }

    public static Singleton Instance
    {
        get
        {
            if (m_instance == null)
            {
                m_instance = new Singleton();
            }
            return m_instance;
        }
    }

    private void MyTimerCallBack(object state)
    {
        //******** Update the list by interval here ******************

        m_cacheObjects = UpdateTheList();
    }

    public void CallMe()
    {
        foreach (CustomObject obj in m_cacheObjects)
        {
            // do something here based on obj

            // The question is, does the m_cacheObjects is thread safe??
            // what happen if the m_cacheObjects is changed
            // during the loop interation?
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

CallMe方法将由Web服务调用:

  [WebMethod]
    public void CallMeWebService()
    {
        Singleton.Instance.CallMe();
    }
Run Code Online (Sandbox Code Playgroud)

问题:1)m_cacheObjects是否是线程安全的?如果在循环交互期间(在CallMe()中)m_cacheObjects被更改(因为计时器)会发生什么?

2)在调用Webservice CallMeWebService()时是否会创建新线程?

Mar*_*ell 8

1:不,静态列表不是自动线程安全的; 你必须m_cacheObjects手动保护

2:这是一个实现细节; 乍一看,它似乎将自己暴露为同步方法,但它如何做到完全取决于它

实际上,你的静态初始化也不是线程安全的; 我可以强制使用两个不同Singleton实例的场景.生产它需要重复,但它会发生.

坦率地说,除非你有充分的理由不这样做,否则最简单但最安全的单身人士模式就是:

private static readonly Singleton m_instance = new Singleton();
Run Code Online (Sandbox Code Playgroud)


Mit*_*hon 5

这是关于如何以线程安全的方式实现单例模式的非常好的资源:http://msdn.microsoft.com/en-us/library/ff650316.aspx

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
     if (instance == null) 
     {
        lock (syncRoot) 
        {
           if (instance == null) 
          instance = new Singleton();
        }
     }

     return instance;
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

这只是确保永远不会有多个实例。您还需要为您的自定义方法应用锁定。

public void CallMe()
{
    lock (syncRoot) 
    {
        foreach (CustomObject obj in m_cacheObjects)
        {
            // do something here based on obj
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Downvoter 如果我应得的,我不介意投反对票,但是您能在其中发表评论吗?事实上,无论我说什么,其他回答者之一似乎都想把我推到答案列表中。 (4认同)

Grh*_*rhm 5

我建议你有关于如何在http://csharpindepth.com/Articles/General/Singleton.aspx上创建线程安全单例的文章.


k1l*_*r8e 5

//using System.Runtime.CompilerServices;

private static volatile Singelton _instance;

public static Singelton Instance
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get
    {
        if (_instance == null)
        {
            _instance = new Singelton();
        }
        return _instance;
    }
}
Run Code Online (Sandbox Code Playgroud)

说明:

[MethodImpl(MethodImplOptions.Synchronized)]这将告诉编译器对"Instance"的访问是"已同步",因此系统会关注对此Parameter的调用.

这是线程安全的.

编辑:(另外,"Lock()"示例不安全!因为,你可以通过"Monitor.Exit(Singleton);"来禁用线程安全性