Объект безопасности резьбы - статический или нет?

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

Ну, правильно объяснив lock(), он сказал, что не стоит ставить объект как статический.

private static readonly object _syncLock = new object();

Он утверждал, что причина в том, что статический объект делает этот объект более медленным для блокировки потоков, чем если бы он был нестационарным. Это правда?

EDIT: Тем не менее я все еще не уверен. В чем разница между этими тремя подходами?

private static readonly object _syncLock = new object();
public static readonly object _syncLock = new object();
private readonly object _syncLock = new object();

Ответ 1

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

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

Ответ 2

Он утверждал, что причина в том, что статичность запускается во время выполнения вместо компиляции и сделает этот объект более медленным для блокировки потоков, чем если бы он был нестационарным.

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

Ответ 3

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

О, и здесь отличная статья Джеффри Рихтера о правильном использовании блокировки.:)

Ответ 4

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

Предположим, что у вас есть классы List, со специальным методом Reorder, который принимает некоторые странные аргументы. Подумайте, нужно ли переупорядочивать 100 разных списков во время некоторых параллельных процессов. Вам остается только, чтобы разные потоки не манипулировали одним и тем же списком одновременно, поскольку это может повлиять на вашу логику переупорядочения. Вам не нужна статическая блокировка, так как вам все равно, когда манипулируют разными списками одновременно.

Простым примером сценария со статической блокировкой является инициализация некоторых статических данных, где вы хотите убедиться, что логика нагрузки запускается только один раз. Как некоторый кеш или синглтон.

Ответ 5

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

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

Ответ 6

Другие верны, что выбор использования статического поля экземпляра зависит от того, какое состояние (уровень класса или уровня экземпляра) необходимо блокировать, и нет никакой разницы в скорости самой блокировки. НО, если вам действительно нужно использовать данные экземпляра, ваше приложение может работать намного быстрее, используя lock(this), а не блокировать все потоки от доступа к данным любого экземпляра. Возможно, это было то, что получал интервьюер - в приложении, где несколько потоков используют только данные экземпляра, он должен работать быстрее, если вы только блокируете экземпляр, потому что он не будет блокировать другие потоки от использования других экземпляров.

И наоборот, если потоки получают доступ к состоянию на уровне класса (статического), вам необходимо заблокировать их одним объектом. Когда мне нужно это сделать, шаблон, который я использовал, - это заблокировать тип класса следующим образом:

[Edit - не такая хорошая идея, в конце концов, см. комментарии ниже]

lock(typeof(MyClass))
{
  // use class-level data
}

Это позволяет избежать необходимости создания поля статического объекта.