Почему объект блокировки должен быть статическим?

112

Очень часто используется частный статический объект только для чтения для блокировки в многопоточности. Я понимаю, что private уменьшает количество точек входа в объект блокировки, ужесточая инкапсуляцию и, следовательно, доступ к наиболее важным.

Но почему статика?

private static readonly object Locker = new object();

В конце концов, поле используется только в моем классе, и я мог бы просто использовать это вместо этого:

private readonly object Locker = new object();

Любые комментарии?

ОБНОВИТЬ:

В качестве примера я вставил этот код (просто пример). Я мог бы использовать статический или нестатический шкафчик для этого, и оба будут работать нормально. Учитывая ответ ниже, я должен скорее определять свой шкафчик следующим образом? (Извините, у меня собеседование на следующей неделе, и мне нужно знать все детали :)

private readonly object Locker = new object();

А вот код:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

Спасибо

Houman
источник
15
Насколько мне известно, static обычно используется, чтобы сделать его независимым от экземпляра. Если существует несколько экземпляров MyWorkerClass, только один может работать с заданными данными одновременно (при условии, что все они используют общие ресурсы).
Брэд Кристи,
2
В редакции отсутствует важная деталь: где они _serviceи где находятся _waithandle? пример? статический? Другой? Это может быть , например, преднамеренная синхронизация доступа к удаленному серверу ...
Марк Грейвелл
правильно, со вторым редактированием: да, с этого конца вы можете заблокировать каждый экземпляр. Однако, возможно , были причины сделать его статическим - если исходный разработчик хотел (как уже упоминалось) синхронизировать доступ, чтобы сервер получал только один запрос сразу из этого AppDomain ... Я не могу знать, так ли это , или это было просто случайно.
Марк Гравелл

Ответы:

177

«Не очень распространено использование частного статического объекта, доступного только для чтения, для блокировки в многопоточности» - скорее, обычно используется блокировка с соответствующей / выбранной степенью детализации . Иногда так бывает static. Чаще, ИМО, это не так, но основано на экземплярах .

В основном, вы видите staticблокировку для глобального кеша или для отложенной загрузки глобальных данных / синглтонов. И в последнем случае, есть лучшие способы сделать это в любом случае .

Так что все действительно зависит: как это Lockerиспользуется в вашем сценарии? Является ли она защищать то , что является само по себе статический? В таком случае блокировка должна быть статичной. Если он защищает что-то, что основано на экземпляре , то IMO блокировка также должна быть основана на экземпляре.

Марк Гравелл
источник
24
Не могли бы вы подробнее рассказать о том, как лучше отложить загрузку глобальных данных?
bizi
Я всегда использую static / volatile, потому что, если есть несколько мест, где он основан на экземпляре, я все равно хотел бы контролировать доступ к моему методу / переменной потокобезопасным способом. Многие экземпляры могут обращаться к одним и тем же ресурсам, и я хочу это контролировать. Я тоже хотел бы увидеть лучшее от этого. У вас отличный представитель, и я уверен, что ваш ответ будет столь же хорош для меня. Ответьте, пожалуйста?
Эндрю Симпсон
82

Он не обязательно должен быть статичным, на самом деле иногда он не должен быть статичным.

Переменная должна находиться в той же области видимости, что и методы, в которых вы ее используете для блокировки. Если методы являются статическими, переменная должна быть статической, а если методы являются методами экземпляра, переменная должна быть переменной экземпляра.

Статическая переменная по-прежнему будет работать при использовании для блокировки в методе экземпляра, но тогда вы будете блокировать слишком много. Вы заблокируете все методы во всех экземплярах, а не только методы в одном экземпляре.

Guffa
источник
28
+1 за «а-ха» ... Вы заблокируете все методы во всех экземплярах, а не только методы в одном экземпляре.
radarbob
3
@radarbob - Незначительная деталь: вы не заблокируете все методы, которые вы просто заблокируете, что может заинтересовать больше клиентов. Методы никогда не блокируются, просто мьютекс был занят.
Erno
Я подозреваю, что формулировка этого ответа может вводить в заблуждение - блокировка не должна иметь ничего общего с объемом методов - она ​​должна касаться только объема общих данных, к которым осуществляется доступ в этих методах. Метод экземпляра может не иметь доступа к каким-либо общим данным (и, следовательно, не требует блокировки), может обращаться к статическим общим данным (и, следовательно, требуется статическая блокировка, также может быть хорошей идеей вместо этого рефакторинг), то же самое для статических ...
Алексей Левенков
@AlexeiLevenkov: Вы правы, что на самом деле объем должен определяться тем, являются ли данные статическими или нет, но объем методов также должен определяться этим, так что все это совпадает. Данные экземпляра обычно не нуждаются в блокировке, но если экземпляр используется совместно между потоками, вам потребуется блокировка.
Guffa
28

Объем и время жизни блокировки могут / должны зависеть от «объекта», который вы хотите заблокировать. Статические замки в основном используются для блокировки статических вещей.

Эрно
источник
3
Незначительная деталь: замок не статичен, объект, который вы используете для идентификации блокировки, статичен. Еще одна небольшая деталь: вы не запираете «вещи».
Guffa
2
Да, я думаю, что если мы попытаемся запереть не те «вещи», они могут оказаться слишком большими и сильными и однажды сбежать.
ProfK
12
@Guffa Это странно, в комментарии выше вы правильно сказали: «Вы просто слишком усложняете», теперь я вижу, что за 1 минуту до того, как сказать это, похоже, вы слишком усложняли вещи :)
Николас Петерсен