10

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

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?
        }
    }
}

Web 服务将调用 CallMe 方法:

  [WebMethod]
    public void CallMeWebService()
    {
        Singleton.Instance.CallMe();
    }

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

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

4

6 回答 6

8

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

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

实际上,您的静态初始化也不是线程安全的。我可以暴力破解Singleton使用两个不同实例的场景。产生它需要重复,但它会发生。

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

private static readonly Singleton m_instance = new Singleton();
于 2012-07-26T08:20:33.050 回答
6
//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;
    }
}

解释:

[MethodImpl(MethodImplOptions.Synchronized)]这将告诉编译器对“Instance”的访问是“Synchronized”,因此系统会注意对该参数的调用。

这是线程安全的。

编辑:(此外,“Lock()”示例不安全!因为,您可以使用“Monitor.Exit(Singleton);”禁用线程安全性)

于 2014-09-06T10:43:49.563 回答
4

This is a pretty good resource on how to implement the singleton pattern in a thread safe way: 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;
      }
   }
}

This simply makes sure that there will never be more than one instance. You also need to apply locking for your custom method.

public void CallMe()
{
    lock (syncRoot) 
    {
        foreach (CustomObject obj in m_cacheObjects)
        {
            // do something here based on obj
        }
    }
}
于 2012-07-26T08:19:27.510 回答
0

它不是线程安全的。

我相信我会在“MyTimerCallBack”和“CallMe”方法中使用

于 2012-07-26T08:21:33.827 回答
0

1)不,m_cacheObjects不是线程安全的。

2)是的,将创建新线程(嗯,它可能不是新线程,而是从线程池中获取的线程)。

你需要m_cacheObjectslock声明来保护。此外,在 CallMe 方法中,我建议创建以下内容的本地副本m_cacheObjects

// create new field syncRoot
private static readonly object syncRoot = new object();

新的 CallMe 方法:

List<CustomObject> localCopy;
lock (syncRoot)
{
    localCopy = new List<CustomObject>(m_cacheObjects);
}

foreach (var nextObject in localCopy)
{
// Do some work
}

并更新MyTimerCallBack方法:

lock (syncRoot)
{
    m_cacheObjects = UpdateTheList();
}

并且还请实现线程安全的单例(详细阅读其他答案)。

于 2012-07-26T08:33:42.710 回答