ConcurrentModificationException

Iniciado por w00t;, 10 Diciembre 2009, 15:22 PM

0 Miembros y 1 Visitante están viendo este tema.

w00t;

Bueno estoy teniendo un problema al modifcar una lista, me está tirando un error de concurrencia (java.util.ConcurrentModificationException)

El bloque de código que genera problema, es el siguiente

Código (java) [Seleccionar]

if(celdaAux.getMalos()!= null && celdaAux.getFuego() == true){
for(Malo m : celdaAux.getMalos()){
m.matar(getBomberman(1));
celdaAux.removeMalo(m);
celdaAux.setfueModificada(true);
}



Investigué un poco, y encontré que el problema se da por que estoy eliminando elementos de una lista mientras estoy iterando sobre la misma.
Una solución a esto es usando el remove del iterador. No me funcionó
Y otra usando un bloque syncronized(){...}, pero no sé como aplicarlo

Casidiablo

Como bien dices, puedes usar syncronized bien sea en cada método en donde accedas a la lista o creando un bloque dentro del método. Aquí tienes una explicación:

http://epere4.blogspot.com/2008/04/cmo-funciona-synchronized-en-java.html

Un saludo!

w00t;

He leído lo que me dejaste, pero sigo sin poder solucionar el problema.

La excepción que se produce es la siguiente


Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
at java.util.LinkedList$ListItr.next(Unknown Source)
at juego.Nivel.checkColisiones(Nivel.java:164)
at frontend.GUI_Principal.chekearColisiones(GUI_Principal.java:341)
at frontend.GUI_Principal.game(GUI_Principal.java:325)
at frontend.GUI_Principal.main(GUI_Principal.java:346)


Por esto entiendo que, cuando la clase Nivel quiso acceder al método checkColisiones() se produjo el error por que ya había un objeto GUI_Principal, accediendo a este por medio de la llamada chekearColisiones().

Como debería aplicar el syncronized? Destaco que nivel, no tiene una referencia al unico objeto del tipo GUI_Principal que hay en ejecución

Leyer

#3
es complicado ayududate sin el code completo prueba syncronizando el metodo o el obj de class que llamas para el metodo checkColisiones() y si esta en un hilo recuerda syncronizar el metodo run

SL2


w00t;

#4
Sinceramente estoy estancado, no encuentro solución. He puesto y sacado syncronized por todos lados ya ^^

Pongo los fragamentos de código de las clases involucradas en el error, no pongo las clases completas por que son cientos de líneas.  No quería recurrir a esto de ponerles el código ya que el trabajo de debuggear es mío, pero ya estoy frustado xD

El error

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
at java.util.LinkedList$ListItr.next(Unknown Source)
at juego.Nivel.checkColisiones(Nivel.java:165)
at frontend.GUI_Principal.chekearColisiones(GUI_Principal.java:396)
at frontend.GUI_Principal.game(GUI_Principal.java:378)
at frontend.GUI_Principal.main(GUI_Principal.java:401)


Ahora el codigo de clases, les marco las lineas q indica el error
Código (java) [Seleccionar]


public class Nivel {
protected java.util.LinkedList<Malo> cMalos;

/**
* Retorna la lista de malos del nivel
* @return
*/
public LinkedList<Malo> getMalos(){
return cMalos;
}


/**
* Retorna la celda x,y
* @param x
* @param y
* @return
*/
public Celda getCelda(int x, int y)
{
return tablero[x][y];
}

/**
* Chekea colisiones en la celda (x,y)
* @param x
* @param y
*/
public void checkColisiones(int x, int y) {
Celda celdaAux = getCelda(x,y);


//Colsion Malo - Fuego
//(LINEA 165)
                if(celdaAux.getMalos()!= null && celdaAux.getFuego() == true){
for(Malo m : celdaAux.getMalos()){
m.matar(getBomberman(1));
celdaAux.removeMalo(m);
celdaAux.setfueModificada(true);
}
}
      }


}


Código (java) [Seleccionar]

public class GUI_Principal extends Canvas implements KeyListener{

/**
* Ciclo del juego
*/
public void game() {
Graphics g = this.getGraphics();
inicializar();
//Input de teclado
addKeyListener(this);
timer.start();
while (isVisible() && !b.getMurio()) {
chekearColisiones();
paintTablero();
jLabel2.setText(Integer.toString(b.getScore()));
jLabel4.setText(timer.getResult());
g.drawImage(buffer, 0, 0, this);
try {
Thread.sleep(b.getVel());
} catch (InterruptedException e) {}
}
System.out.println("te moriste pete");
}

/**
* Chekea las colisiones en todas las celdas de la matriz
*/
private  void chekearColisiones() {
for(int i=0;i<n.matriz_width;i++)
for(int j=0;j<n.matriz_height;j++)
//LINEA 396
                                n.checkColisiones(i, j);
}

public static void main(String[] args) {
GUI_Principal gui = new GUI_Principal();
gui.game();
}
}

Leyer

mm pero no veo que nivel este llamando este llamando a checkColisiones()..  bueno si dices que colocaste syncronized por todos lados jeje bueno  intenta esto cuando la class  nivel intente acceder checkColisiones() coloca un wait anterior a las sentencias dond se llama al metodo checkColisiones() en la gui entonces cuando el nivel termine de hacer su "tarea" con el checkColisiones() notificas el la gui para que esta continue..

Saludos.

w00t;

El unico que llama a checkColisiones() es GUI_Principal. Nivel nunca lo llama

Creo q  el error se produce por que cuando checkColisiones esta recorriendo/modificando la lista cMalos, hay otro hilo que la esta iterando. Puede ser?

w00t;

#7
Si el problema era ese, encontré la solución acá:

http://www.coderanch.com/t/233932/Threads-Synchronization/java/deal-with-Concurrent-Modification-Exception

http://www.javalobby.org/java/forums/t76297.html

Seguí esos tips y funcionó todo correctamente!

Estaba usando bien el syncronized, pero tenia que eliminar con el remove del iterador ademas de sincronizarlo.

Desde ya, gracias por la ayuda L-EYER y Casidiablo.