保持静态 volatile ISessionFactory
Keep static volatile ISessionFactory
我有一个像这样的单例会话工厂实现:
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,我会从这个更改中获得一些好处吗?或者这是一个很好的实践模式?
如果您只是从 _instance 字段中删除 volatile,您的代码将不再是线程安全的。
如果你真的想保留 "famous" 双重检查锁定技术,你可以从你的 _instance 字段中删除 volatile 但你需要修改分配看起来像这样:
var tmp = new MySessionFactory();
Volatile.Write(ref _instance, tmp);
这会给您带来一些好处,因为 _instance 字段不再易失,因此所有读取都不是易失的(一些性能提升)。但是我们有 volatile 赋值,可以保证代码仍然是线程安全的。
我个人的意见 - 不要使用双重检查锁定技术。如果你真的需要惰性初始化,请使用 Lazy class。如果你不需要 100% 延迟初始化就这样写:
private static readonly MySessionFactory _instance = new MySessionFactory();
此初始化将由静态 class 构造函数调用,该构造函数在代码第一次尝试访问 class 的成员时自动调用。在 CLR 中,构造函数在设计上是线程安全的,因此在这种情况下您无需担心并发性。并且由于在您的情况下,您没有 class 中与 MySessionFactory _instance 无关的任何成员,因此该解决方案的行为将与双重检查锁一样惰性。
如果您想了解更多相关信息,Jeffrey Richters 的书 CLR via C# 中有一整章叫做 "The Famous Double-Check Locking Technique"。好好读书;)
我有一个像这样的单例会话工厂实现:
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,我会从这个更改中获得一些好处吗?或者这是一个很好的实践模式?
如果您只是从 _instance 字段中删除 volatile,您的代码将不再是线程安全的。
如果你真的想保留 "famous" 双重检查锁定技术,你可以从你的 _instance 字段中删除 volatile 但你需要修改分配看起来像这样:
var tmp = new MySessionFactory();
Volatile.Write(ref _instance, tmp);
这会给您带来一些好处,因为 _instance 字段不再易失,因此所有读取都不是易失的(一些性能提升)。但是我们有 volatile 赋值,可以保证代码仍然是线程安全的。
我个人的意见 - 不要使用双重检查锁定技术。如果你真的需要惰性初始化,请使用 Lazy class。如果你不需要 100% 延迟初始化就这样写:
private static readonly MySessionFactory _instance = new MySessionFactory();
此初始化将由静态 class 构造函数调用,该构造函数在代码第一次尝试访问 class 的成员时自动调用。在 CLR 中,构造函数在设计上是线程安全的,因此在这种情况下您无需担心并发性。并且由于在您的情况下,您没有 class 中与 MySessionFactory _instance 无关的任何成员,因此该解决方案的行为将与双重检查锁一样惰性。
如果您想了解更多相关信息,Jeffrey Richters 的书 CLR via C# 中有一整章叫做 "The Famous Double-Check Locking Technique"。好好读书;)