Единственное, что я могу придумать, чтобы учесть нулевые записи, - это одновременный доступ. List<>
не является поточно-ориентированным, в конце концов.
Вот и все. Нам специально сказано, что он не является поточно-ориентированным, поэтому мы не должны удивляться, что одновременный доступ приводит к нарушению контракта.
Относительно того, почему возникает эта конкретная проблема, мы можем только предположить, поскольку частная реализация List<>
, ну, в общем, частная ( Я знаю, что у нас есть Reflector и Shared Source - но в принципе это частная ). Предположим, что реализация включает в себя массив и «последний заполненный индекс». Предположим также, что «Добавить предмет» выглядит так:
- Убедитесь, что массив достаточно велик для другого элемента
- последний заполненный индекс <- последний заполненный индекс + 1 </li>
- массив [последний заполненный индекс] = входящий элемент
Теперь предположим, что есть два потока, вызывающих Add. Если последовательность операций чередования заканчивается так:
- Тема A: последний заполненный индекс <- последний заполненный индекс + 1 </li>
- Тема B: последний заполненный индекс <- последний заполненный индекс + 1 </li>
- Тема A: массив [последний заполненный индекс] = входящий элемент
- Тема B: массив [последний заполненный индекс] = входящий элемент
тогда не только будет null
в массиве, но и элемент, который поток А пытался добавить, вообще не будет в массиве!
Так вот, я не точно знаю , как List<>
внутренне работает. У меня есть половина памяти, что это с ArrayList
, который внутренне использует эту схему; но на самом деле это не имеет значения. Я подозреваю, что любой любой механизм списков, который предполагается запустить не одновременно, может быть сломан при одновременном доступе и достаточно «неудачном» чередовании операций. Если мы хотим обеспечить безопасность потоков от API, который его не предоставляет, у нас есть , чтобы выполнить некоторую работу самостоятельно - или, по крайней мере, мы не должны удивляться, если API иногда ломает его, когда мы не т.
Для вашего требования
Я не хочу, чтобы вызывающие потоки блокировали ожидание добавления своего элемента
моей первой мыслью была очередь Multiple Producer-Single-Consumer, в которой потоки, желающие добавить элементы, являются производителями, которые отправляют элементы в очередь асинхронно, и есть один потребитель, который извлекает элементы из очереди и добавляет их в список с соответствующей блокировкой. Моя вторая мысль заключается в том, что мне кажется, что это будет тяжелее, чем того требует ситуация, поэтому я позволю себе немного обдумать.