Iterator w kolekcjach i zmiana stanu obiektów

0

Zmieniając coś w obiektach umieszonych w kolekcji powoduje wyjątek java.util.ConcurrentModificationException.

Kolekcja(tu: eventList) jest przeglądana w poniższym kodzie przez ListIterator. Wywołanie metody action() powoduje zmainy stanów obiektów kolekcji albo wstawienie nowych obiektów.

Uruchomienie metody ( action() )zmieniającej coś w kolekcji w momencie gdy ta kolekcja jest obslugiwana przez Iterator powoduje wyjątek. Czy java rozwiązuje taki problem?

public class Conrtoller 
{
	private LinkedList<Event> eventList=new LinkedList<Event>();
	public void addEvent(Event c){ eventList.add(c);}
	public void run()
	{		
		ListIterator<Event> it=eventList.listIterator();
		while(it.hasNext()){
			if(it.next().ready())
			{
				System.out.println(it.previous());
				it.next().action();
				it.remove();
			}	
		}
	}
}
0

synchronizedList

btw. podawałem to jakiś tydzień temu

0

nie wiem, nie pomaga. Taki sam wyjątek( java.util.ConcurrentModificationException) powstaje też gdy nie używam iteratora ale swobodnego dostępu do kolekcji.
Oto przykładowy kod. Zawiera klase, kolekcje obiektów tej klasy oraz dwie metody coś tam zmieniające.

import java.util.*;
/**
 * przykladowy obiekt
 */
class Budynek 
{
	private String name;
	public Budynek(){name="unknown";}
	public Budynek(String name){this.name=name;	}
}
/**
 * zmieniacz 1
 */
public class ZarzadcaBud
{

	List<Budynek> rzad=Collections.synchronizedList(new ArrayList<Budynek>() );//   lista którz jest zmieniana w dwuch miejscach
	public ZarzadcaBud() {     //wypelnienie listy
		rzad.add(new Budynek());
		rzad.add(new Budynek("Merkury"));
		rzad.add(new Budynek("Apollo"));
		rzad.add(new Budynek());
	}
	public void zarz()// pierwsze miejsce w ktorym sa wykonywane zmiany listy
	{
		NowyZarz nz=new NowyZarz();
		synchronized(rzad)
		{
			Iterator it=rzad.iterator();
			while(it.hasNext())
			{
				nz.zarz( (Budynek)it.next(), rzad);   //<---wywolanie drugiego miejsca zmieniajacego liste
				it.remove();
			}
		}
	}
	public static void main(String args[])
	{
		ZarzadcaBud zb=new ZarzadcaBud();
		zb.zarz();
	}
}
/**
 * zmieniacz 2
 */
class NowyZarz
{
	public void zarz(Budynek b, List<Budynek> rzad)      //    druga metoda zmieniajaca liste
	{
		synchronized(rzad)
		{
			rzad.add(b);
		}
	}
}

0

Z iterowanej kolekcji można usuwać elementy (it.remove()), ale nigdy nie można dodawać elementów w czasie iteracji.

Musisz stworzyć drugą listę(kopię pierwszej, np. poprzez "nowaLista = new ArrayList(staraLista)"). Iterujesz po pierwszej, a zmieniasz drugą. Po skończonej iteracji robisz "staraLista = nowaLista; nowaLista = null;".
Niestety takie podejście zwiększa złożoność do O(n^2), więc przemyśl, czy na pewno potrzebujesz dodawania elementów w czasie iteracji.

Nie ma to nic wspólnego z synchronizacją. Synchronizacja jest potrzebna, gdy masz więcej wątków.

0

Skoro używasz ArrayList to może zamiast iteratorów użyj zwyczajnych indeksów ? Spadku wydajności nie będzie bo iteratory i tak korzystają z get i remove.

1 użytkowników online, w tym zalogowanych: 0, gości: 1