Здесь есть два отдельных вопроса:
- Использовать ли один комбинированный замок или два отдельных замка
- Использовать ли для блокировки отдельные объекты или сами списки (или их
SyncRoot
s)
Они до некоторой степени разделимы - в том случае, если вы используете две отдельные блокировки, вы можете создать два отдельных объекта для блокировки, по одному для каждого списка.
Если вы хотите, чтобы MethodThatUsesAList
и MethodThatUsesBList
могли работать одновременно, вам понадобятся две отдельные блокировки. Затем вам нужно будет убедиться, что каждый раз, когда вы можете приобрести оба замка, вы приобретаете их в том же порядке. Это означает рассуждение обо всем коде внутри любого метода, который получает блокировку: вам нужно убедиться, что он не вызывает другой метод , который получает другую блокировку, например.
Если ваш конкретный сценарий вряд ли сильно пострадает от всех методов, эффективно блокируемых для других потоков каким-либо одним потоком, выполняющим любой из них, тогда я бы использовал один замок просто для простоты.
В любом случае, я бы лично использовал "закрытые" блокировки, о которых никакой другой код не знает. Мне проще рассуждать о коде, написанном таким образом. Использование самого списка или корня синхронизации вполне может быть вполне приемлемым, но я просто предпочитаю думать о блокировках, которые больше ничего не могут получить.