Podejdę do tego, ukrywając wszystkie rzeczywiste iteratory na liście wewnątrz klasy opakowania i ukrywając samą listę w jej własnej opakowaniu. Okienko listy będzie wiedzieć o wszystkich opakowaniach iteracyjnych; na add()
, musiałby wymusić na każdym opakowaniu iteratora, aby zapisać bieżącą pozycję, usunąć wewnętrzny iterator, a następnie wykonać faktyczne dodawanie (które mogłoby uniknąć wyjątku ConcurrentModificationException, ponieważ cały iterator został zniszczony), a następnie mieć wszystkie opakowania iteracyjne ponownie utworzyć swoje iteratory i ustawić je w odpowiedniej pozycji.Ponieważ wydajesz się dodawać tylko do końca listy, żadne wymyślne indeksowanie nie będzie konieczne, ale będziesz musiał dowiedzieć się, co dzieje się z iteratorami, które już przeszły do końca - czy są na końcu, czy na ich oryginalnym pozycja na liście? Niektórzy z nich oczywiście mogli już powiedzieć swoim rozmówcom, że hasNext()
jest fałszywa ... Jeszcze jedna rzecz: add()
i get()
powinienem uważać za synchronized
.
Oto testowe rozwiązanie zgodne z tymi wytycznymi. PureListWrapper i PureIteratorWrapper, jak sugerują nazwy, po prostu przekazują wszystkie wywołania metod do elementu, który zawijają.
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import junit.framework.TestCase;
public class ConcurrentlyAddableListTest extends TestCase {
public void testAdd() throws Exception {
List<String> list = new ConcurrentlyAddableList<String>();
list.add("apple");
list.add("banana");
Iterator<String> a = list.iterator();
Iterator<String> b = list.iterator();
b.next();
Iterator<String> c = list.iterator();
c.next();
c.next();
list.add("cherry");
assertEquals("apple", a.next());
assertEquals("banana", b.next());
assertEquals("cherry", c.next());
}
private static class ConcurrentlyAddableList<T> extends PureListWrapper<T> {
private final Set<WrappedIterator<T>> iterators = new HashSet<WrappedIterator<T>>();
@Override
public Iterator<T> iterator() {
WrappedIterator<T> iterator = new WrappedIterator<T>(super.iterator());
iterators.add(iterator);
return iterator;
}
@Override
public synchronized boolean add(T o) {
final HashSet<WrappedIterator<T>> set = new HashSet<WrappedIterator<T>>(iterators);
for (WrappedIterator<T> iterator : set)
iterator.rememberPosition(this);
boolean result = super.add(o);
for (WrappedIterator<T> iterator : set)
iterator.restorePosition(this);
return result;
}
}
private static class WrappedIterator<T> extends PureIteratorWrapper<T> {
private int index = 0;
public WrappedIterator(Iterator<T> iterator) {
super(iterator);
}
@Override
public T next() {
index++;
return super.next();
}
public void restorePosition(List<T> list) {
setIterator(list.iterator());
int prevIndex = index;
index = 0;
while (index < prevIndex)
next();
}
public void rememberPosition(List<T> list) {
setIterator(null);
}
}
}
Powinieneś umieścić swój kod w istocie na github lub bardziej szczegółowo, jakie są twoje wymagania. Czy chciałbyś "wstawić" elementy do drugiej głowy, czy raczej potrzebujesz sieci linków? – Karussell
ile "głów"? 2, czy arbitralne – Bozho
zrobić wiele iteratorów na liście, że zwraca 'Collections.synchronizedList()'? – thejh