Пример кода бесполезен - как упоминает @Jon, все потоки будут блокировать свой собственный объект, что означает, что они вообще не будут блокировать друг друга. Можно также полностью исключить оператор блокировки.
Прежде всего, вам нужно заблокировать объект, который является общим для всех потоков (например, сам список). Например:
lock (aList)
aList.Add("abc");
Что касается «почему», внутренняя реализация Списка может (выполняет) выполнять действия, которые небезопасно выполнять параллельно в нескольких потоках. Это задокументировано в Списке классов MSDN документы :
Открытые статические (Shared в Visual Basic) члены этого типа являются нитями
безопасный. Любые члены экземпляра не гарантированно являются потокобезопасными.
Список может одновременно поддерживать несколько читателей, если
Коллекция не изменена. Перечисление через коллекцию
по сути не потокобезопасная процедура. В редком случае, когда
перечисление конкурирует с одним или несколькими доступом к записи, единственный способ
обеспечить безопасность потока, чтобы заблокировать коллекцию в течение всего
перечисление. Чтобы разрешить доступ к коллекции несколькими
темы для чтения и записи, вы должны реализовать свои собственные
синхронизации.