Structuremap单例线程安全吗?

时间:2010-03-26 10:29:14

标签: c# singleton thread-safety structuremap

目前我有以下课程:

    public class PluginManager
{
    private static bool s_initialized;
    private static object s_lock = new object();

    public static void Initialize() {
        if (!s_initialized) {
            lock (s_lock) {
                if (!s_initialized) {
                    // initialize

                    s_initialized = true;
                }
            }
        }
    }
}

重要的是,Initialize()只应在应用程序运行时执行一次。我以为我会把它重构成一个单例类,因为这样会更安全吗?:

    public sealed class PluginService
{
    static PluginService() { }
    private static PluginService _instance = new PluginService();
    public static PluginService Instance { get { return _instance; } }

    private bool s_initialized;

    public void Initialize() {
        if (!s_initialized)
        {
            // initialize

            s_initialized = true;
        }
    }
}

问题一,是否仍然需要锁定(我已将其删除),因为我们只会在同一个实例上工作?

最后,我想使用DI和结构图初始化我的服务,所以我重构如下:

    public interface IPluginService {
    void Initialize();
}

public class NewPluginService : IPluginService
{
    private bool s_initialized;
    public void Initialize() {
        if (!s_initialized) {
            // initialize

            s_initialized = true;
        }
    }
}

在我的注册表中:

            ForRequestedType<IPluginService>()
            .TheDefaultIsConcreteType<NewPluginService>().AsSingletons();

这按预期工作(单例在以下代码中返回true):

            var instance1 = ObjectFactory.GetInstance<IPluginService>();           
        var instance2 = ObjectFactory.GetInstance<IPluginService>();

        bool singleton = (instance1 == instance2);

所以我的下一个问题是,结构图解决方案与单例类一样是线程安全的(第二个例子)。唯一的缺点是,这仍然允许直接实例化NewPluginService(如果不使用结构图)。

非常感谢, 本

1 个答案:

答案 0 :(得分:3)

我会提出几点建议:

  • 布尔标志应为volatile
  • 制作您的单身实例readonly
  • 初始化不是线程安全的,无论你只有一个实例......所以它应该是同步的

    public sealded class PluginService
    {
    
    static PluginService() { }
    
    //make the instance readonly
    private static readonly PluginService _instance = new PluginService();
    public static PluginService Instance { get { return _instance; } }
    
    // make the flag volatile
    private static volatile bool s_initialized = false;
    private static object s_lock = new object();
    
    
    // you still need to synchronize when you're initializing
    public void Initialize() {
        lock(s_lock)
        {
            if (!s_initialized)
            {
                // initialize
    
                    s_initialized = true;
                }
            }
        }
    }
    

结构化地图上没有争用,因此其线程安全性似乎没有受到影响......

你拥有的单例类不是线程安全的。要记住的主要事情是单个实例不能确保单个线程只能访问它。如果有多个线程具有对该实例的引用,则该实例及其所持有的数据存在争用。如果存在争用,则应确保线程安全(至少同步)。