Ответ 1
- Это как задокументировано - если он не использует никаких блокировок, это использование не может вызвать каких-либо взаимоблокировок.
- Представьте, что у вас есть ленивое значение, которое вы инициализируете путем чтения из базы данных, но вы хотите, чтобы в любой момент обращался к БД только одному потоку. Если у вас есть другой код, который обращается к БД, у вас может быть тупик. Рассмотрим следующий код:
void Main()
{
Task otherThread = Task.Factory.StartNew(() => UpdateDb(43));
Thread.Sleep(100);
Console.WriteLine(lazyInt.Value);
}
static object l = new object();
Lazy<int> lazyInt = new Lazy<int>(Init, LazyThreadSafetyMode.ExecutionAndPublication);
static int Init()
{
lock(l)
{
return ReadFromDb();
}
}
void UpdateDb(int newValue)
{
lock(l)
{
// to make sure deadlock occurs every time
Thread.Sleep(1000);
if (newValue != lazyInt.Value)
{
// some code that requires the lock
}
}
}
Init()
считывает из БД, поэтому он должен использовать блокировку. UpdateDb()
записывается в БД, поэтому ему тоже нужна блокировка, и поскольку Lazy
в этом случае также использует блокировку внутри, он вызывает тупик.
В этом случае было бы легко устранить тупик, перемещая доступ к lazyInt.Value
в UpdateDb()
вне оператора блокировки, но это может быть не так тривиально (или очевидно) в других случаях.