0

У меня есть реализация на сессию завода быть синглтон так:Держите статический летучий 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, я буду получать некоторые преимущества с этим изменением? Или это образец хорошей практики?

+0

Если вы используете Lazy , вы достигнете той же цели с чистым кодом IMHO. –

ответ

1

Если вы просто удалите volatile из своего поля _instance, ваш код больше не будет потокобезопасным.

Если вы действительно хотите сохранить «знаменитую» двойную проверку техники запирающих вы можете удалить летучие из вашего поля _instance, но тогда вам нужно изменить назначение, чтобы выглядеть следующим образом:

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

Это даст вам некоторая польза, потому что поле _instance больше не изменчиво, поэтому все чтения не являются изменчивыми (некоторое усиление производительности). Однако у нас есть изменчивое назначение, которое гарантирует, что код по-прежнему является потокобезопасным.

Мое личное мнение - не используйте метод двойной проверки. Если вам действительно нужна ленивая инициализация, используйте класс Lazy. Если вам не нужно 100% ленивая инициализация просто написать это:

private static readonly MySessionFactory _instance = new MySessionFactory(); 

Этой инициализация будет вызываться конструктором статического класса, который автоматически вызывается первый тайм-код пытается получить доступ к члену класса. В конструкторах CLR потоки безопасны по дизайну, поэтому вам не нужно беспокоиться о параллелизме в этом случае. И так как в вашем случае у вас нет членов этого класса, которые не связаны с MySessionFactory _instance, это решение будет вести себя как ленивое, как блокировка двойной проверки.

Если вы хотите больше узнать об этом, то в книге Джеффри Рихтера есть целая глава CLR via C#, названная «Известная техника блокировки с двойной проверкой». Хорошее чтение;)