Чому об’єкт блокування повинен стати статичним?


112

Дуже часто застосовувати приватний статичний об'єкт для читання лише для блокування в декількох нитках. Я розумію, що приватне зменшує вхідні точки до блокуючого об'єкта, затягуючи капсуляцію і, отже, доступ до найважливішого.

Але чому статичний?

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();
        }

Дякую


15
Наскільки мені відомо, статику зазвичай використовують, щоб зробити її екземпляром-агностиком. Якщо існує декілька екземплярів "MyWorkerClass", лише один може запускати дані дані одночасно (за умови, що всі вони використовують спільні ресурси).
Бред Крісті

2
В редакції відсутня важлива деталь: де _serviceі де _waithandleрозташовані? екземпляр? статичний? інший? Це може , наприклад, бути навмисно синхронізації доступу до віддаленого сервера ...
Марк Gravell

правильно, з другою редакцією: так, з цього кінця речей, які ви могли заблокувати за певний примірник. Там можуть бути причини , щоб зробити його статичним, хоча - якщо вихідний DEV хотів (як уже згадувалося) для доступу Синхронізувати так , що сервер отримує тільки один запит відразу від цього AppDomain ... Я не знаю , що то справа чи це було просто випадково.
Марк Гравелл

Відповіді:


177

Це не "дуже часто використовувати приватний статичний об'єкт для читання лише для запису в багатопотоковій різьбі", - скоріше, використовувати замок у відповідній / обраній деталізації . Іноді це так static. Частіше, IMO, це не так, - але базується на екземплярі .

Основний час, коли ви бачите staticблокування, - це глобальний кеш, або для відкладеного завантаження глобальних даних / одиночних клавіш. І в останньому, є кращі способи зробити це все одно .

Тож насправді залежить: як це Lockerвикористовується у вашому сценарії? Це захищає щось, що саме по собі є статичним? Якщо так, замок повинен бути статичним. Якщо це захищає щось таке, що є екземпляром на основі, то IMO замок повинен також бути екземпляром на основі.


24
Чи можете ви детальніше розказати про кращий спосіб відкладеного завантаження глобальних даних?
bizi

Я завжди використовую статичну / мінливу, тому що якщо є декілька місць, де це заснований на екземплярі, я все одно хотів би контролювати, щоб мій метод / змінна була доступна безпечним способом. Багато випадків можуть отримати доступ до одних і тих же ресурсів, і я хочу це контролювати. Я теж хотів би бачити краще робити це. У вас є прекрасний представник, і я впевнений, що ваша відповідь буде однаково чудова для мене. Будь-ласка дайте відповідь?
Ендрю Сімпсон

82

Це не повинно бути статичним, адже іноді це не повинно бути бути статичним.

Змінна повинна жити в тій самій області, що і методи, де ви використовуєте її для блокування. Якщо методи статичні, змінна повинна бути статичною, а якщо методи - це примірними методами, змінна повинна бути екземпляром змінною.

Статична змінна все ще працюватиме, коли використовується для блокування методу екземпляра, але тоді ви будете занадто заблоковані. Ви заблокуєте всі методи в усіх екземплярах, а не лише методи в одному екземплярі.


28
+1 для "а-ха" ... Ви заблокуєте всі методи в усіх примірниках, а не лише методи в одному екземплярі.
radarbob

3
@radarbob - Незначна деталь: Ви не заблокуєте всі методи, ви просто зафіксуєте замок, який може зацікавити більше клієнтів. Методи ніколи не блокуються, це лише те, що була взята мютекс.
Ерно

Я підозрюю, що формулювання цієї відповіді може ввести в оману - блокування не повинно робити нічого із застосуванням методів - воно має стосуватися лише обсягу спільних даних, до яких можна отримати доступ до цих методів. Метод екземпляра може не отримувати доступу до будь-яких спільних даних (а отже, і не потрібно блокувати), може отримувати доступ до статичних спільних даних (а значить, потрібен статичний блокування, а також рефакторинг може бути гарною ідеєю натомість), такий же як для статичного ...
Олексій Левенков,

@AlexeiLevenkov: Ви маєте рацію, що область дійсності повинна вирішуватись, чи є дані статичними, чи ні, але обсяг методів також повинен вирішуватись таким чином, так що все це поєднується разом. Дані екземплярів зазвичай не потребують блокування, але якщо екземпляр поділяється між потоками, вам знадобиться блокування.
Гуффа

28

Обсяг та термін служби замка можуть / повинні залежати від "речі", яку ви хочете заблокувати. Статичні замки в основному використовуються для фіксації статичних речей.


3
Незначна деталь: Замок не є статичним, об'єкт, який ви використовуєте для ідентифікації блокування, є статичним. Ще одна незначна деталь: Ви не зачиняєте "речі".
Guffa

2
Так, я думаю, якщо ми спробуємо зафіксувати неправильні "речі", вони можуть бути занадто великими і сильними, і одного разу втекти.
ПрофК

12
@Guffa Це дивно, у коментарі вище ви справедливо сказали: "Ви просто надмірно ускладнюєте речі", тепер я бачу 1 хвилину, перш ніж сказати, що, здається, ви надмірно ускладнювали речі :)
Ніколас Петерсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.