ConcurrentModificationException nicht nachvollziehbar

Status
Nicht offen für weitere Antworten.

DrLoad

Mitglied
Hi,

zu dieser Exception gibts ja eine Menge Lesestoff, ich habe jedoch einen Fall, wo sie meines Wissens nicht auftreten dürfte, es aber trotzdem tut. Der Code ist nichtmal besonders kompliziert:

Java:
	private Map<Integer,Scriptable> scripts = Collections.synchronizedMap(new HashMap<Integer, Scriptable>());

	@Override
	public void run() {
		while( true ) {
			synchronized(scripts){
				Vector<Scriptable> c = new Vector<Scriptable>();
				c.addAll(scripts.values());
				for(Scriptable script : c){
					if( script.isFinished()) scripts.remove(new Integer(script.getId()));
				}				
			}
			try {
				Thread.sleep( 500L );
			}
			catch( Exception x ) {
				x.printStackTrace(System.out);
			}
		}		
	}

	public void addScript( Scriptable script ){
		synchronized(scripts){
			scripts.put(new Integer(script.getId()), script);
		}
	}

Die ConcurrentModificationException tritt ja dann auf, wenn
- mehrere Threads auf eine Resource zugreifen oder
- ein einziger Thread eine Liste o. ä. verändert, während er über sie iteriert.

Beide Fälle meine ich im Code ausgeschlossen zu haben. Die kritischen Bereiche habe ich in einem synchronized - Block und Elemente werden aus der Original Map entfernt, während über eine vorher angelegte Kopie iteriert wird.

Habe ich einen Stolperstein übersehen?

Ich bin für jede Hilfe dankbar.
 
S

SlaterB

Gast
da du selber
synchronized(scripts){
benutzt, kannst du dir Collections.synchronizedMap() sparen,
die Methoden der Map werden nie für sich aufgerufen, sondern bei dir immer in einem sicheren Block

ich behaupte jetzt erstmal auch, dass das so sicher ist, treten bei dir Exceptions auf?
es fehlt ein vollständiges Programm, mit Thread-Klasse, main-Methode und Gesamtablauf
 

DrLoad

Mitglied
Danke für die Antwort. Ja, die Exception sieht bei mir folgendermaßen aus:

Code:
Exception in thread "Scripting-Thread" java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
        at java.util.HashMap$ValueIterator.next(HashMap.java:821)
        at scripts.ScE.run(ScE.java:19)
        at java.lang.Thread.run(Thread.java:619)

Den Rest des Codes hielt ich für unwesentlich, hier aber nochmal die vollständige Klasse. Der Thread wird indirekt von der JVM gestartet und läuft vor sich hin, während andere Threads darauf zugreifen.

Java:
public class ScE implements Runnable {

	private Thread runner = null;

	private static ScE instance =  new ScE();

	private Map<Integer,Scriptable> scripts = Collections.synchronizedMap(new HashMap<Integer, Scriptable>());

	private ScE(){
		runner = new Thread(this, "Scripting-Thread");
        runner.start();  
	}

	@Override
	public void run() {
		while( true ) {
			synchronized(scripts){
				Vector<Scriptable> c = new Vector<Scriptable>();
				c.addAll(scripts.values());
				for(Scriptable script : c){
					if( script.isFinished()) scripts.remove(new Integer(script.getId()));
				}				
			}
			try {
				Thread.sleep( 500L );
			}
			catch( Exception x ) {
				x.printStackTrace(System.out);
			}
		}		
	}

	public void addScript( Scriptable script ){
		synchronized(scripts){
			scripts.put(new Integer(script.getId()), script);
		}
	}

	public static ScE getInstance(){
		return instance;
	}	
}

P.S. Laut Doku habe ich es so verstanden, dass man trotz "Collections.synchronizedMap" alle Zugriffe auf die gelieferte Map in synchronized Blöcken kapseln soll.
 

KrokoDiehl

Top Contributor
Kann es sein, dass folgender Block
[JAVA=18]
Vector<Scriptable> c = new Vector<Scriptable>();
c.addAll(scripts.values());
for(Scriptable script : c){
if( script.isFinished()) scripts.remove(new Integer(script.getId()));
}
[/code]
dennoch deinen Vektor verändert? Denn
Code:
c.addAll()
fügt keine Kopien, sondern Referenzen deiner Scriptable-Objekte ein. Durch das
Code:
scripts.remove()
wird also am Ende auch dein Vektor
Code:
c
beeinflusst.
Naja, das ist meine Vermutung, wobei ich mir da eher unsicher bin.
Zum Testen kannst du aber mal folgende Variante probieren:
Java:
Vector<Integer> toDelete = new Vector<Integer>();
for (Scriptable script : scripts)
{
    if (script.isFinished())
        toDelete.add(script.getID());
}

// nun das Entfernen
for (Integer id : toDelete)
    scripts.remove(id);
 
S

SlaterB

Gast
@DrLoad
na die Klasse sagt für sich nunmal nichts über den Gesamtablauf aus,
hier mal ein Testprogramm:
Java:
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        ScE e = ScE.getInstance();
        while (true)
        {
            e.addScript(new Scriptable());
            System.out.println("added");
            Thread.sleep(100);
        }
    }
}


class ScE
    implements Runnable
{

    private Thread runner = null;

    private static ScE instance = new ScE();

    private Map<Integer, Scriptable> scripts = Collections.synchronizedMap(new HashMap<Integer, Scriptable>());

    private ScE()
    {
        runner = new Thread(this, "Scripting-Thread");
        runner.start();
    }

    public void run()
    {
        try
        {
            rrun();
        }
        catch (Exception x)
        {
            x.printStackTrace(System.out);
        }

    }

    private void rrun()
        throws Exception
    {
        long time = System.currentTimeMillis();
        while (true)
        {
            synchronized (scripts)
            {
                Vector<Scriptable> c = new Vector<Scriptable>();
                c.addAll(scripts.values());
                System.out.println((System.currentTimeMillis() - time) + " - start  run: " + scripts.size());
                for (Scriptable script : c)
                {
                    if (script.isFinished()) scripts.remove(new Integer(script.getId()));
                    Thread.sleep(50L);
                }
                System.out.println((System.currentTimeMillis() - time) + " - finish run: " + scripts.size());
            }
            Thread.sleep(500L);
        }
    }

    public void addScript(Scriptable script)
    {
        synchronized (scripts)
        {
            scripts.put(new Integer(script.getId()), script);
        }
    }

    public static ScE getInstance()
    {
        return instance;
    }
}


class Scriptable
{
    static int count = 0;

    private int id = count++;

    public boolean isFinished()
    {
        return Math.random() < 0.2;
    }

    public int getId()
    {
        return id;
    }
}
Code:
16 - start  run: 0
16 - finish run: 0
added
added
added
added
added
516 - start  run: 5
766 - finish run: 2
added
added
added
added
added
1266 - start  run: 7
1625 - finish run: 5
added
added
added
added
added
2125 - start  run: 10
2625 - finish run: 7
added
added
added
added
added
3125 - start  run: 12
3735 - finish run: 10
added
added
added
added
added
4235 - start  run: 15
5000 - finish run: 12
added
added
added
added
added
5500 - start  run: 17
6360 - finish run: 16
added
added
added
added
added
6860 - start  run: 21
7922 - finish run: 15
added
added
added
added
added
8422 - start  run: 20
9438 - finish run: 17
added
added
added
added
added
9938 - start  run: 22
11063 - finish run: 17
added
added
added
added
added
11563 - start  run: 22
12672 - finish run: 13
added
added
added
added
added
13172 - start  run: 18
14094 - finish run: 16
added
added
added
added
added
14594 - start  run: 21
...

keine Exceptions, und ich persönlich habe leider weiterhin auch keine Fantasie, mir einen möglichen Grund für eine Exception auszudenken,
mir scheint das narrensicher

ich könnte gar behaupten, dass die Exception, so wie da steht (15:19), gar nicht auftreten kann,
den StackTrace bekomme ich bei

for (Scriptable script : scripts.values())

wenn alles synchronisierende wegfällt, denn bei derartigen Code landet man von der Runnable-Methode aus direkt im Iterator,

wenn aber addAll() benutzt wird, dann müsste das im StackTrace als eine Zeile auftauchen

-----

> P.S. Laut Doku habe ich es so verstanden
glaube ich gerne, aber ist ja kein entscheidendes Kriterium ;)


> Durch das scripts.remove() wird also am Ende auch dein Vektor c beeinflusst.

das glaube ich nicht
 
Zuletzt bearbeitet von einem Moderator:

DrLoad

Mitglied
Ich bedanke mich herzlich für die Antworten und besonders bei dir SlaterB für die Mühe und den Test des Programms.
Tatsächlich hatte ich zwischenzeitlich eine ähnliche Lösung, wie sie KrokoDiehl vorgeschlagen hat in Verwendung (also mit Delete Liste), was aber nichts half, daher passt die Exception nicht so ganz zum Code :) .

Leider kann ich den Fehler nicht gezielt reproduzieren, aber ich bin schon mal froh, dass eurer Einschätzung nach das Ding soweit sicher sein sollte.

P.S. Was habe ich denn falsch verstanden?

Java:
 Map m = Collections.synchronizedMap(new HashMap());
      ...
  Set s = m.keySet();  // Needn't be in synchronized block
      ...
  synchronized(m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

Muss m nicht auf jeden Fall im sync sein, wenn man iterieren will?
 
S

SlaterB

Gast
so wie es da steht ist beides richtig,
synchronized{ } für den Iterator,
keySet() sicher, da Map synchronisiert ist

wenn du aber keySet() sowie alle anderen Map-Methoden eh nur in synchronized{ }-Blocks aufrufst, wie in ScE der Fall,
dann ist es unnötig, extra eine Collections.synchronizedMap() zu verwenden, dann klappt es mit einer normalen Map genauso
 

DrLoad

Mitglied
Danke, wieder was gelernt!

Wird denn, wenn ich sowas habe:
Java:
for (Scriptable script : scripts.values())
intern ein Iterator erzeugt, d.h müßte das auch in einen synchronized Block?

Woanders habe ich gelesen, dass man mit "ConcurrentHashMap" (für den Preis von Effizienz) so eine Art Rundumsorglos Paket erhält was Threadsicherheit angeht. Würdet ihr das auch so sehen?
 
S

SlaterB

Gast
> müßte das auch in einen synchronized Block?

das müsste, und wenn nicht gibts wie gesagt genau deine Exception, abgesehen von rrun() bei mir:
Java:
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        ScE e = ScE.getInstance();
        while (true)
        {
            e.addScript(new Scriptable());
            System.out.println("added");
            Thread.sleep(100);
        }
    }
}

class ScE
    implements Runnable
{
    private Thread runner = null;
    private static ScE instance = new ScE();
    private Map<Integer, Scriptable> scripts = new HashMap<Integer, Scriptable>();

    private ScE()
    {
        runner = new Thread(this, "Scripting-Thread");
        runner.start();
    }

    public void run()
    {
        try
        {
            rrun();
        }
        catch (Exception x)
        {
            x.printStackTrace(System.out);
            System.exit(0);
        }
    }

    private void rrun()
        throws Exception
    {
        long time = System.currentTimeMillis();
        while (true)
        {
            Vector<Scriptable> c = new Vector<Scriptable>();
            c.addAll(scripts.values());
            System.out.println((System.currentTimeMillis() - time) + " - start  run: " + scripts.size());
            for (Scriptable script : scripts.values())
            {
                if (script.isFinished()) scripts.remove(new Integer(script.getId()));
                Thread.sleep(50L);
            }
            System.out.println((System.currentTimeMillis() - time) + " - finish run: " + scripts.size());

            Thread.sleep(500L);
        }
    }

    public void addScript(Scriptable script)
    {
        scripts.put(new Integer(script.getId()), script);
    }

    public static ScE getInstance()
    {
        return instance;
    }
}


class Scriptable
{
    static int count = 0;

    private int id = count++;

    public boolean isFinished()
    {
        return Math.random() < 0.2;
    }

    public int getId()
    {
        return id;
    }
}
Code:
added
0 - start  run: 1
47 - finish run: 1
added
added
added
added
added
547 - start  run: 6
added
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
	at java.util.HashMap$ValueIterator.next(HashMap.java:822)
	at test.ScE.rrun(Test.java:65)
	at test.ScE.run(Test.java:46)
	at java.lang.Thread.run(Thread.java:619)

----

Iterator natürlich, so ist das bei for-each-Schleifen

-----

ich persönlich halte von Collections.synchronizedMap() nichts, allein schon weil ich nicht weiß, ob auch das Durchlaufen solcher Iteratoren sicher ist,
nach deinem Posting von 16.18 (// Must be in synchronized block) siehts da ja schlecht aus,

meine Philiosophie ist bisher, dass das Synchronisieren derart selten und so wichtig ist,
dass man da ruhig selber synchronized{} schreiben kann, gar immer eine eigene Klasse wie deine Klasse ScE,
auf die Map sollte niemand direkt zugreifen dürfen, sondern nur vorgegebene Methoden wie ScE.add(),
und dann ist es ja leicht da selber synchronized{}-Blöcke hinzuschreiben,

Collections.synchronizedMap() kann ich persönlich nichts abgewinnen,

falls ConcurrentHashMap was anderes ist, kann ich dazu nichts sagen, außer das gleiche, falls es ähnlich ist ;)
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
G ConcurrentModificationException - finds nicht Allgemeine Java-Themen 5
M ConcurrentModificationException Allgemeine Java-Themen 2
D java.util.ConcurrentModificationException tritt auf Allgemeine Java-Themen 12
F ConcurrentModificationException warum ? Allgemeine Java-Themen 7
K Collections java.util.ConcurrentModificationException Allgemeine Java-Themen 3
N ConcurrentModificationException Allgemeine Java-Themen 2
S java.util.ConcurrentModificationException - aber nur ein Thread Allgemeine Java-Themen 3
D java.util.ConcurrentModificationException - per Copy vermeiden Allgemeine Java-Themen 11
D java.util.ConcurrentModificationException bei ArrayList Allgemeine Java-Themen 2
F ConcurrentModificationException Allgemeine Java-Themen 2
P Vectoren bearbeiten: ConcurrentModificationException Allgemeine Java-Themen 4
B ConcurrentModificationException Allgemeine Java-Themen 3
S Fehler ConcurrentModificationException Allgemeine Java-Themen 8
R java.util.ConcurrentModificationException vermeiden? Allgemeine Java-Themen 8
R ConcurrentModificationException Allgemeine Java-Themen 9
K Threading - schreiben auf Hashmap/löschen - ConcurrentModificationException Allgemeine Java-Themen 3
J java.util.ConcurrentModificationException bei HashMap? Allgemeine Java-Themen 2
G ConcurrentModificationException Allgemeine Java-Themen 4
E ConcurrentModificationException Allgemeine Java-Themen 6
R ConcurrentModificationException trotz synchronized? Allgemeine Java-Themen 12
P java.util.ConcurrentModificationException Allgemeine Java-Themen 9
M ConcurrentModificationException Allgemeine Java-Themen 6
S ConcurrentModificationException Allgemeine Java-Themen 4
Zrebna Wieso sollte man Null-Prüfungen nicht mit Optional-Objekten nutzen? Allgemeine Java-Themen 13
kodela Textfeld nicht rechteckig Allgemeine Java-Themen 10
G Doppelklick auf Javaprogramm klapt nicht Allgemeine Java-Themen 1
W Timer terminiert nicht Allgemeine Java-Themen 5
D Linux, Java-Version wird nicht erkannt bzw. welche Einstellung fehlt noch? Allgemeine Java-Themen 19
W Überflüssige Deklaration vermeiden...war da nicht mal was? Allgemeine Java-Themen 3
N lwjgl kann textureSampler nicht finden Allgemeine Java-Themen 4
P Fehler: Hauptklasse Main konnte nicht gefunden oder geladen werden Ursache: java.lang.ClassNotFoundException: Main Allgemeine Java-Themen 24
S Java Programm lässt sich vom USB-Stick starten, aber nicht von HDD Allgemeine Java-Themen 16
T .Jar kann man nicht ausführen Allgemeine Java-Themen 18
P JDK nicht installiert in Net Object Fusion Allgemeine Java-Themen 7
D Image bewegt sich nicht nach Klicken auf Button Allgemeine Java-Themen 15
N Regex schlägt nicht an Allgemeine Java-Themen 10
Y Wieso krieg ich die Unit Tests nicht hin Allgemeine Java-Themen 55
D Erste Schritte Mp3 Datei kann nicht von der Festplatte geöffnet werden - mit ChatGPT erstellt Allgemeine Java-Themen 7
G Popup wird nicht sichtbar Allgemeine Java-Themen 9
8u3631984 Funktions Parameter mit Lombok "NonNull" annotieren wird in Jacococ Testcoverage nicht herausgefiltert Allgemeine Java-Themen 3
kodela String kann nicht zu Pfad konvertiert werden Allgemeine Java-Themen 16
M Apache Proxy Weiterleitung auf Tomcat funktioniert nicht wie gewünscht Allgemeine Java-Themen 1
Momo16 Brauche Hilfe - Java Projekt kann nicht erstellt werden Allgemeine Java-Themen 12
OnDemand ApacheCommon FTP Client zuckt nicht Allgemeine Java-Themen 3
T JavaPoet - (noch) nicht existente Typen Allgemeine Java-Themen 2
E Es ist nicht möglich, eine Batch-Anweisung auszuführen. Allgemeine Java-Themen 9
C Was passt hier nicht bei der Calendar-Class Allgemeine Java-Themen 2
T Testing JUnit5: try ... catch arbeitet nicht sauber Allgemeine Java-Themen 6
W While Schleife funktioniert nicht ganz Allgemeine Java-Themen 4
OnDemand MemoryLeak nicht zu finden Allgemeine Java-Themen 26
torresbig Website login Problem - Jsoup, wie bisher, klappt nicht! Allgemeine Java-Themen 31
H do-while Schleife funktioniert nicht wie ich es möchte Allgemeine Java-Themen 7
ERlK JDA Code funktioniert nicht? Allgemeine Java-Themen 4
OnDemand Ram Freigabe erfolgt nicht nach Prozessende Allgemeine Java-Themen 18
OnDemand XML desializing Attribute bringt nicht erwartetes Ergebnis Allgemeine Java-Themen 16
T ImageIcon wird nicht angezeigt Allgemeine Java-Themen 6
N JAVA-Code mit Grafikfenster zeichnet in Windows, aber nicht Mac. Allgemeine Java-Themen 4
stormyark TikTakToe funktioniert nicht Allgemeine Java-Themen 10
N Warum wird die For Schleife nicht betreten Allgemeine Java-Themen 4
Tiago1234 Hauptklasse konnte nicht gefunden oder geladen werden Allgemeine Java-Themen 38
T Remove bei ArrayList funktioniert nicht Allgemeine Java-Themen 2
M Map<String,String>funktioniert nicht richtig Allgemeine Java-Themen 4
I "Neues" Lizenzmodell Oracle - JRE nicht mehr zur Redistribution freigegeben? Allgemeine Java-Themen 16
J c Programm läuft nicht in compilierter Version des Java Projektes Allgemeine Java-Themen 7
A code wird nicht ausgeführt Allgemeine Java-Themen 3
Blender3D Alte Beiträge nicht mehr vorhanden Allgemeine Java-Themen 6
M Warum hat Java dieses und jenes nicht... Allgemeine Java-Themen 8
W Bilder werden in App mit Jar-Datei nicht angezeigt Allgemeine Java-Themen 15
Micha43 Applet *.jar läuft nicht auf dem Mac Allgemeine Java-Themen 8
M Warum bekommen ich den Result nicht ? Allgemeine Java-Themen 17
Kiki01 Häufigster Buchstabe lässt sich nicht ermitteln Allgemeine Java-Themen 30
OnDemand RegEx /compilebekomme nicht die erwarteten Werte Allgemeine Java-Themen 9
HerrBolte Seltsamer Fehler nur in der Windows- und nicht in der Java-Console O_O Allgemeine Java-Themen 16
P String.replace() funktioniert nicht? Allgemeine Java-Themen 3
N nicht einsehbarer Fehler im code, kann nicht mehr übersetzten Allgemeine Java-Themen 51
P Karate API Test läuft nicht durch . initializationError Allgemeine Java-Themen 21
N nicht static und auch nicht new Allgemeine Java-Themen 3
Z macOS java konnte nicht entfernt werden xpc verbindungsfehler Allgemeine Java-Themen 4
T Schaltfläche wird nicht gefunden Allgemeine Java-Themen 4
boschl2000 Springerproblem-Implementierung funktioniert nicht richtig Allgemeine Java-Themen 1
F Getter Methode aufrufen funktioniert nicht Allgemeine Java-Themen 1
N Gierigen Regex in nicht-gierigen umwandeln Allgemeine Java-Themen 4
N Regulärer Ausdruck funktioniert nicht Allgemeine Java-Themen 6
AleXusher Hauptklasse startlösung konnte nicht gefunden oder geladen werden Allgemeine Java-Themen 1
G @PostConstruct Annotation nicht mehr gültig ? Allgemeine Java-Themen 7
L Objekte in Set nicht gefunden Allgemeine Java-Themen 13
T Projekt baut nicht mehr/lässt sich nicht mehr ausführen Allgemeine Java-Themen 6
izoards log4j2 will nicht.... Allgemeine Java-Themen 15
Tobero Meine Funktion für das beinhalten eines Punktes in einem Kreis funktioniert nicht Allgemeine Java-Themen 5
1Raini Java if-Abfrage funktioniert nicht! Allgemeine Java-Themen 3
D Firebase retrieve data Problem, Child Element wird nicht angesprochen Allgemeine Java-Themen 0
I serialVersionUID - explizit vergeben oder nicht? Allgemeine Java-Themen 6
MiMa Vorhandenes das nicht existiert?? Allgemeine Java-Themen 7
LimDul Hä? Lambda-Ausdruck geht, Methoden-Referenz nicht Allgemeine Java-Themen 8
O Jar lässt sich auf bestimmten Pc nicht starten Allgemeine Java-Themen 18
T Fremde Typen mockt man nicht? Allgemeine Java-Themen 3
Killunox MaxHeap Zuweisung unter Linux funktioniert nicht Allgemeine Java-Themen 1
LimDul Direktes return eines Array geht nicht Allgemeine Java-Themen 20
B neuroph hält beim XOR lernen nicht an Allgemeine Java-Themen 13
kodela JDialog zeigt Text nicht an Allgemeine Java-Themen 5

Ähnliche Java Themen

Neue Themen


Oben