Абстрактных от JCIPитераторов для коллекций копирования при записи
итераторы для копирования при записи коллекции сохранить ссылку на массив подложки, которая была тока в начале итерации, а так как это никогда не изменится, им нужно только ненадолго синхронизировать с , чтобы обеспечить видимость содержимого массива.
Итераторов, возвращаемых коллекциями копирования при записи не бросают ConcurrentModificationException и возвращают элементы точно так, как они были на момент создания итератора, независимо от последующих модификаций
Глядя на исходный код на #CopyOnWriteArrayList.iterator()
956 public Iterator<E> iterator() {
957 return new COWIterator<E>(getArray(), 0); // call to private constructor
958 }
993 private final Object[] snapshot;
994
995 private int cursor;
996
997 private COWIterator(Object[] elements, int initialCursor) {
998 cursor = initialCursor;
999 snapshot = elements;
1000 }
Вы видите, что snapshot
указывает на массив, возвращаемый getArray()
, и поскольку возвращаемая ссылка массива нестабильна, любое изменение ссылочной переменной гарантированно будет отражено. (Создание ссылки на массив неустойчивой не делает на каждое месте индекса летучих элементов)
, где изменение в массиве выполняются внутренней сторонка
386 public E More ...set(int index, E element) {
387 final ReentrantLock lock = this.lock;
388 lock.lock();
389 try {
390 Object[] elements = getArray();
391 E oldValue = get(elements, index);
392
393 if (oldValue != element) {
394 int len = elements.length;
395 Object[] newElements = Arrays.copyOf(elements, len);
396 newElements[index] = element;
397 setArray(newElements);
398 } else {
399 // Not quite a no-op; ensures volatile write semantics
400 setArray(elements);
401 }
402 return oldValue;
403 } finally {
404 lock.unlock();
405 }
406 }
setArray(newElements);
т.е., как показано в способе.
где GetArray()
92 final Object[] More ...getArray() {
93 return array;
94 }
& setArray (...)
final void More ...setArray(Object[] a) {
100 array = a;
101 }
являются операции на этом неустойчивом массиве
private volatile transient Object[] array;
Clearl y, итератор возвращает массив, который (if) был изменен, а не тот, который был создан в начале процесса итерации.
Итак, что же автор щенного
возвращает элементы точно так, как они были в то время итератора был созданного, независимо от последующих изменений.
Я посмотрел код, который вы разместили здесь, и ясно, итератор возвращает массив, который никогда не был изменен. –
@MarkoTopolnik: Но в то же время другие потоки могут явно модифицировать его через 'set (int index, E element) .' –
*« Очевидно, что итератор возвращает массив »* Ehh, nooo. «Ясно», итератор * использует * массив, полученный во время создания итератора *. Любая последующая модификация списка создаст * новый * массив, поэтому итератор не увидит эти изменения. – Andreas