2016-11-18 3 views
1

Мне любопытно узнать о различии ниже двух примеров.блокировка целевым объектом self

случай 1) блокировка от чтения объекта

private readonly object key = new object(); 
private List<int> list = new List<int>; 
private void foo() 
{ 
    lock(key){ 
     list.add(1); 
    } 
} 

Случай 2.) замок самой

private List<int> list = new List<int>; 
private void foo() 
{ 
    lock(list){ 
     list.add(1); 
    } 
} 

оба случая потокобезопасные достаточно целевого объекта? Мне интересно, если сборщик мусора меняет адрес переменной list (например, 0x382743 => 0x576382) в какой-то момент, чтобы он мог не работать поточно-безопасным.

ответ

2

Пока List<T> не имеет в своем коде каких-либо lock(this) заявлений две функции будут вести себя одинаково.

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

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

private List<int> list = new List<int>; 
private void foo() 
{ 
    lock(((ICollection)list).SyncRoot){ 
     list.add(1); 
    } 
} 

Это internally просто делает то же самое, как вы делали и создали отдельный new Object(), чтобы привязываться.

1

В обоих случаях foo() является потокобезопасным. Но замок на отдельный объект только для чтения (случай 1), является предпочтительным, так как

  • вам не придется беспокоиться о том, не является ли список пустой (блокировка будет потом не)
  • вам не придется беспокоиться о ли список переназначен (назначение нового экземпляра List<T> в список может вызвать некоторые проблемы, например, потеря атомарности заблокированного блока кода)
  • вам не нужно беспокоиться о том, передаете ли вы список стороннему коду (например, в результате какой-либо функции), поскольку хорошей практикой является блокировка только объектов, которые у вас есть под вашим эксклюзивным контролем (это может привести к тупиковой ситуации, если другой объект может заблокировать и этот объект).
  • :
  • Когда блокировка защищает больше объектов одновременно (например, list1, list2 и т. Д.), Блокировка только на одном из них все равно будет работать (если вы будете блокировать последовательно на одном и том же объекте повсюду), но приведет к менее читабельному и более сложному понимать код.

Блокировка гарантированно работает нормально, даже если сборщик мусора перемещает объект, за которым вы блокируете.

Смежные вопросы