Примечание: я допускаю исключение, когда изменение коллекции во время итерации уже исправлено
Словарь не является потокобезопасной коллекцией, а это означает, что не безопасен для изменения и чтения коллекции из разных потоков без внешней синхронизации. Hashtable является (был?) Поточно-ориентированным для сценария «один писатель - много читателей», но Dictionary имеет другую внутреннюю структуру данных и не наследует эту гарантию.
Это означает, что вы не можете изменять свой словарь, когда вы получаете доступ к нему для чтения или записи из другого потока, он может просто сломать внутренние структуры данных. Блокировка ключа не защищает внутреннюю структуру данных, поскольку при изменении этого ключа кто-то может читать другой ключ вашего словаря в другом потоке. Даже если вы можете гарантировать, что все ваши ключи являются одними и теми же объектами (как сказано об интернировании строк), это не принесет вам уверенности. Пример:
- Вы блокируете ключ и начинаете изменять словарь
- Другой поток пытается получить значение для ключа, который попадает в тот же сегмент, что и заблокированный. Это происходит не только тогда, когда хеш-коды двух объектов совпадают, но чаще, когда хеш-код% tableSize одинаков.
- Оба потока обращаются к одному и тому же сегменту (связанный список ключей с одинаковым значением хеш-кода% tableSize)
Если в словаре нет такого ключа, первый поток начнет изменять список, а второй поток, скорее всего, прочитает неполное состояние.
Если такой ключ уже существует, детали реализации словаря могут по-прежнему изменять структуру данных, например, перемещать недавно использованные ключи в начало списка для более быстрого поиска. Вы не можете полагаться на детали реализации.
Есть много подобных случаев, когда у вас будет испорченный словарь. Таким образом, вы должны иметь внешний объект синхронизации (или использовать сам Словарь, если он не открыт для общего доступа) и блокировать его во время всей операции. Если вам нужны более детальные блокировки, когда операция может занять много времени, вы можете скопировать ключи, которые нужно обновить, выполнить итерацию по ним, заблокировать весь словарь во время обновления одного ключа (не забудьте проверить, что ключ все еще там) и отпустить его для пусть запускаются другие темы.