Существует серьезная проблема с методами Synchronized
в старой библиотеке коллекций, которая заключается в том, что они синхронизируются при слишком низком уровне детализации (для метода, а не для единицы работы).
Существует классическое состояние гонки с синхронизированной очередью, показанное ниже, где вы проверяете Count
, чтобы проверить, безопасно ли удалять из очереди, но затем метод Dequeue
выдает исключение, указывающее, что очередь пуста. Это происходит потому, что каждая отдельная операция является поточно-ориентированной, но значение Count
может меняться между запросом и использованием значения.
object item;
if (queue.Count > 0)
{
// at this point another thread dequeues the last item, and then
// the next line will throw an InvalidOperationException...
item = queue.Dequeue();
}
Вы можете безопасно написать это, используя ручную блокировку вокруг всей единицы работы (т. Е. Путем проверки количества и снятия с очереди элемента) следующим образом:
object item;
lock (queue)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}
Так как вы ничего не можете безопасно удалить из синхронизированной очереди, я не стал бы беспокоиться об этом и просто использовал бы ручную блокировку.
.NET 4.0 должна иметь целую кучу правильно реализованных поточно-ориентированных коллекций, но, к сожалению, это еще почти год.