Каково различие (если таковые имеются) между использованием
void MethodName()
{
lock(this)
{
// (...)
}
}
или
private object o = new object();
void MethodName()
{
lock(o)
{
// (...)
}
}
?
Существует ли разница в производительности? Стиль? Поведение?
Разница в том, что любой может заблокировать ваш экземпляр, но только вы можете заблокировать частный объект.
Это помогает предотвратить взаимоблокировки.
Например:
Допустим, Microsoft использовала lock (this)
в классе Control
.
Затем, если кто-то другой заблокирует экземпляр Control
, его блокировка помешает запуску кода в Control
, а это не то, что он хочет.
Это особенно плохо, если вы заблокируете типы, которые являются общими для всех доменов приложений
Шаблон I Обычно для класса, объявленного static
....
public static class SomeClass{ private static object objLock = new object(); .... public static object SomeProperty{ get{ lock(objLock){ // Do whatever needs to be done } } set{ lock(objLock){ } } } }
Точно так же для обычного класса я бы следовал этому шаблону:
public class SomeClass{ private readonly object objLock = new object(); .... public object SomeProperty{ get{ lock(objLock){ // Do whatever needs to be done } } set{ lock(objLock){ } } } }
Таким образом, никто не может заблокировать мой экземпляр и предотвратить возникновение взаимоблокировок ...
Изменить: Я внес поправки в эту статью, чтобы сделать ее более ясной в отношении кода, в котором будет использоваться основа статической блокировки и для обычного класса ... Спасибо Стивену и Далле за их очки ...
Есть разница в объеме и может быть разница в поведении (кстати, MS не рекомендует использовать "this"
// in this case, your lock object is public, so classes outside of this can lock on the same thing
lock(this) {}
// in this case, your lock is private, and only you can issue a lock statement against it
private object lockobj = new object()
..
lock(this.lockobj) {}
// this one is WRONG -- you willget a new object instance every time, so your lock will not provide mutual exclusion
void SomeMethod()
{
// using a local variable for a lock -- wrong
object obj = new object();
lock(obj) {}
}
lock (this)
заблокирует «текущий» объект.
Блокировка «this» обычно плохая идея, поскольку она открывает доступ к блокировке другому коду; Я предпочитаю иметь поле только для чтения, например:
public class Foo
{
private readonly object padlock = new object();
public void SomeMethod()
{
lock(padlock)
{
...
}
}
}
Таким образом, все вызовы SomeMethod
(и все остальное в Foo
, которое блокирует замок
) будут заблокируйте тот же монитор для того же экземпляра Foo
, но ничто другое не может помешать, заблокировав этот монитор.
На самом деле, если вы не имеете дело с «мошенническим» кодом, маловероятно, что другой код действительно заблокирует ссылку на экземпляр Foo
, но это вопрос инкапсуляции.