【问题标题】:Keep static volatile ISessionFactory保持静态 volatile ISessionFactory
【发布时间】:2016-09-16 13:47:18
【问题描述】:

我有一个会话工厂的实现是这样的:

public sealed class MySessionFactory
{
    private static volatile MySessionFactory _instance;
    private ISessionFactory _sessionFactory;
    private static volatile object _locker = new object();

    private MySessionFactory()
    {

    }

    public MySessionFactory Intance
    {
        get
        {
            if (_instance != null)
                return _instance;

            lock (_locker)
            {
                if (_sessionFactory == null)
                {
                    _instance = new MySessionFactory();
                }
            }

            return _instance;
        }
    }

    public ISession OpenSession()
    {
        if (_sessionFactory != null)
            return _sessionFactory.OpenSession();

        lock (_locker)
        {
            if (_sessionFactory == null)
            {
                var cfg = FluentNHibernate.Cfg.Fluently.Configure()
                    .Database(FluentNHibernate.Cfg.Db.PostgreSQLConfiguration.Standard.ConnectionString("connectionString").UseReflectionOptimizer())
                    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsAssembly>());
                _sessionFactory = cfg.BuildSessionFactory();

            }
        }

        return _sessionFactory.OpenSession();
    }
}

如果我删除静态变量 _instance 的 volatile,我会从这个更改中获得一些好处吗?或者这是一个很好的练习模式?

【问题讨论】:

  • 如果您使用 Lazy,您将使用更简洁的代码实现相同的目标,恕我直言。

标签: c# design-patterns nhibernate fluent-nhibernate sessionfactory


【解决方案1】:

如果您只是从 _instance 字段中删除 volatile,您的代码将不再是线程安全的。

如果您真的想保留“著名的”双重检查锁定技术,您可以从您的 _instance 字段中删除 volatile,但是您需要将分配修改为如下所示:

var tmp = new MySessionFactory();
Volatile.Write(ref _instance, tmp);

这会给您带来一些好处,因为 _instance 字段不再是易失性的,因此所有读取都不是易失性的(一些性能提升)。但是,我们有 volatile 分配,可以保证代码仍然是线程安全的。

我的个人意见 - 不要使用双重检查锁定技术。如果您真的需要延迟初始化,请使用 Lazy 类。如果您不需要 100% 延迟初始化,只需这样写:

private static readonly MySessionFactory _instance = new MySessionFactory();

此初始化将由静态类构造函数调用,该构造函数在代码第一次尝试访问类成员时自动调用。在 CLR 中,构造函数在设计上是线程安全的,因此在这种情况下您无需担心并发性。而且由于在您的情况下,您没有与 MySessionFactory _instance 无关的该类的任何成员,因此该解决方案的行为将与双重检查锁一样懒惰。

如果您想了解更多关于这方面的信息,Jeffrey Richters 的书CLR via C# 中有一整章称为“著名的双重检查锁定技术”。好书;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-19
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    相关资源
    最近更新 更多