2015-10-06 5 views
4

Можно ли добавить элементы в LinkedList при повторении?Можно ли добавлять элементы в связанный список при итерации

class Worker { 

    final LinkedList<Foo> worklist = new LinkedList<>(); 

    public void work() { 

     Iterator<Foo> iterator = worklist.iterator(); 

     while (iterator.hasNext()) { 

      Foo foo = iterator.next(); 

      doSomethingWith(foo); 
     } 
    } 

    public void doSomethingWith(Foo foo) { 

     // do something with foo    

     // and possibly add one (or more) foo's to the worklist 
     if (expression) { 
      worklist.add(new Foo()); 
     } 
    } 
} 

Если нет, то как это поведение может быть реализовано безопасным и эффективным способом?

Обратите внимание, что это не about a List, но конкретно о LinkedList. Если это небезопасно, я спрашиваю об альтернативах.

+0

http://stackoverflow.com/questions/3362018/is-linkedlist-thread-safe-when-im-accessing-it-with-offer-and-poll-exclusive Возможность изменять значения в списке при повторении также является свойством, связанным с многопоточным. Общее правило, если список может использовать итератор, он не является потокобезопасным. –

+0

Если вы измените список во время итерации по нему, он выкинет ConcurrentModificationException. – YoungHobbit

+0

Почему бы не использовать ListIterator и добавить элемент с помощью итератора? Мы можем получить к нему доступ с помощью worklist.listIterator() –

ответ

4

Нет, это не безопасно. Следующий код будет бросать ConcurrentModificationException:

final LinkedList<Foo> worklist = new LinkedList<>(); 
worklist.add(new Foo()); 
Iterator<Foo> iterator = worklist.iterator(); 
while (iterator.hasNext()) { 
    Foo foo = iterator.next(); 
    worklist.add(new Foo()); 
} 

LinkedList не отменяет iterator() и реализация по умолчанию, определенные в AbstractSequentialList является вызов listIterator() и LinkedList ли переопределить listIterator.

Цитирование документация LinkedList.listIterator:

Список-итератор отказоустойчивость быстро: если список конструктивно изменен в любое время после итератора создается каким-либо образом, кроме как через list- итератор собственных remove или add методов, список-итератор будет кидать ConcurrentModificationException.

Что вы хотите, чтобы использовать явно в ListIterator, вместо Iterator и использовать ListIterator.add:

final LinkedList<Foo> worklist = new LinkedList<>(); 
worklist.add(new Foo()); 
ListIterator<Foo> iterator = worklist.listIterator(); 
while (iterator.hasNext()) { 
    Foo foo = iterator.next(); 
    iterator.add(new Foo()); 
} 

Новый элемент вставляется перед элементом, который был возвращен next() так последующими обращениями к next() не затронуты. Если вы хотите добавить новый элемент в итерацию, вы можете вызвать previous() (и игнорировать возвращаемое значение) после добавления элемента для перемещения курсора назад.

+0

Но я должен повторить над добавленным элементом тоже. Я редактировал пример кода в вопросе. – Tim

+1

@ Посмотрите мое редактирование, вы можете вызвать 'previous()', чтобы добавить элемент в текущую итерацию. – Tunaki