ConcurrentModificationException??

Dieses Thema im Forum "Programmierung" wurde erstellt von _Baum_, 30. August 2014.

  1. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    Hallo Coder,

    Ich habe eine Exception gefunden! Yay! Das an sich ist ja nicht schwer.
    Aber was genaus soll das sein?

    Code (Text):
    1. [13:40:30 WARN]: [ScorpionPvP] Task #7 for ScorpionPvP v1.0 generated an exception
    2. java.util.ConcurrentModificationException
    3. at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819) ~[?:1.7.0_03]
    4. at java.util.ArrayList$Itr.next(ArrayList.java:791) ~[?:1.7.0_03]
    5. at pluesch.AntiLogout.TaktImpuls(AntiLogout.java:52) ~[?:?]
    6. at pluesch.AntiLogout$1.run(AntiLogout.java:37) ~[?:?]
    7. at org.bukkit.craftbukkit.v1_7_R2.scheduler.CraftTask.run(CraftTask.java:58) ~[spigot.jar:git-Spigot-1360]
    8. at org.bukkit.craftbukkit.v1_7_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:345) [spigot.jar:git-Spigot-1360]
    9. at net.minecraft.server.v1_7_R2.MinecraftServer.v(MinecraftServer.java:618) [spigot.jar:git-Spigot-1360]
    10. at net.minecraft.server.v1_7_R2.DedicatedServer.v(DedicatedServer.java:273) [spigot.jar:git-Spigot-1360]
    11. at net.minecraft.server.v1_7_R2.MinecraftServer.u(MinecraftServer.java:566) [spigot.jar:git-Spigot-1360]
    12. at net.minecraft.server.v1_7_R2.MinecraftServer.run(MinecraftServer.java:472) [spigot.jar:git-Spigot-1360]
    13. at net.minecraft.server.v1_7_R2.ThreadServerApplication.run(SourceFile:618) [spigot.jar:git-Spigot-1360]
    Hier der Code der Klasse:

    Code (Text):
    1. public class AntiLogout implements Listener{
    2.  
    3.     private ArrayList<Player>spieler;
    4.     private ArrayList<Integer>timeout;
    5.  
    6.     private MainFixes main;
    7.     private String prefix;
    8.  
    9.     private Farben farben;
    10.  
    11.     public AntiLogout(MainFixes m)
    12.     {
    13.         m.getServer().getScheduler().scheduleSyncRepeatingTask(m, new Runnable() {
    14.  
    15.             public void run() {
    16.             TaktImpuls();
    17.             }
    18.             }, 60L, 20L);
    19.         spieler = new ArrayList<Player>();
    20.         timeout = new ArrayList<Integer>();
    21.         main=m;
    22.         prefix= main.getPrefix();
    23.         farben= main.getFarben();
    24.     }
    25.  
    26.     protected void TaktImpuls()
    27.     {
    28.         if(!timeout.isEmpty())
    29.         {
    30.             for(Integer i:timeout)//Hier tritt die Excepion auf, da waehrend der Iteration evtl. Eintraege entfernt werden
    31.             {
    32.                 int index=timeout.indexOf(i);
    33.                 if(i<=0)
    34.                 {
    35.                     if(spieler.size()>index)
    36.                     {
    37.                         Player p=spieler.get(index);
    38.                         removePvP(p);//Hier wird ein Eintrag entfernt
    39.                     }
    40.                     else
    41.                     {
    42.                         timeout.remove(i);
    43.                     }
    44.                 }
    45.                 else
    46.                 {
    47.                     timeout.set(index, i-1);
    48.                 }
    49.             }
    50.         }
    51.     }
    52.  
    53.     public void addPvP(Player p)
    54.     {
    55.         if(spieler.contains(p))
    56.         {
    57.             int index= spieler.indexOf(p);
    58.             timeout.remove(index);
    59.             spieler.remove(index);
    60.             BarAPI.removeBar(p);
    61.         }
    62.         else
    63.         {
    64.             if(!p.getWorld().getName().equals("KitPvP"))
    65.             {
    66.                 if(main.istHauptwelt(p.getWorld().getName()))
    67.                 {
    68.                     farben.rotFaerben(p);
    69.                     p.sendMessage(prefix+"§cDu kannst den Spawn nicht mehr betreten!");
    70.                 }
    71.                 p.sendMessage(prefix+"§cFalls du ausloggst wirst du getötet!");
    72.                 p.sendMessage(prefix+"§4*Du bist im PvP-Modus*");
    73.             }
    74.         }
    75.         spieler.add(p);
    76.         timeout.add(8);
    77.         if(p.getWorld().getName().equals("KitPvP"))
    78.         {
    79.             BarAPI.setMessage(p, "§4§l*PvP*", 8);
    80.             return;
    81.         }
    82.         BarAPI.setMessage(p, "§4§l*PvP*", 8);
    83.     }
    84.  
    85.     public void removePvP(Player p)
    86.     {
    87.         if(spieler.contains(p))
    88.         {
    89.             int index= spieler.indexOf(p);
    90.             spieler.remove(index);
    91.             timeout.remove(index);//Entfernung eines Objekts
    92.             p.sendMessage(prefix+"§2*Du bist nicht mehr im PvP-Modus*");
    93.             BarAPI.removeBar(p);
    94.             farben.entfaerben(p);
    95.         }
    96.     }
    97.  
    98.     //Events
    99.     @EventHandler
    100.     public void onPlayerLeave(PlayerQuitEvent e)
    101.     {
    102.         Player p=e.getPlayer();
    103.         if(spieler.contains(p))
    104.         {
    105.             if(main.check(p.getLocation()))
    106.             {
    107.                 p.setHealth(0.0);
    108.             }
    109.             removePvP(p);
    110.         }
    111.     }
    112.  
    113.     @SuppressWarnings("deprecation")
    114.     @EventHandler
    115.     public void PvPInteraktion(EntityDamageByEntityEvent e)
    116.     {
    117.         if(e.getEntity() instanceof Player)
    118.         {
    119.             Player angreifer;
    120.             Player opfer= (Player) e.getEntity();
    121.             Entity damager= e.getDamager();
    122.             if(damager instanceof Projectile)
    123.             {
    124.                 damager=((Projectile) damager).getShooter();
    125.             }
    126.             if(damager instanceof Player)
    127.             {
    128.                 angreifer = (Player) damager;
    129.             }
    130.             else
    131.             {
    132.                 return;
    133.             }
    134.             if(angreifer.equals(opfer))
    135.             {
    136.                 return;
    137.             }
    138.             if(main.istHauptwelt(opfer.getWorld().getName()))
    139.             {
    140.                 if(main.check(angreifer.getLocation())&&main.check(opfer.getLocation())&&!main.hatSchutz(opfer)&&!main.hatSchutz(angreifer))
    141.                 {
    142.                     addPvP(angreifer);
    143.                     addPvP(opfer);
    144.                 }
    145.             }
    146.             else
    147.             {
    148.                 if(main.check(angreifer.getLocation())&&main.check(opfer.getLocation()))
    149.                 {
    150.                     addPvP(angreifer);
    151.                     addPvP(opfer);
    152.                 }
    153.             }
    154.    
    155.         }
    156.     }
    157.  
    158.     @EventHandler
    159.     public void onDeath(PlayerDeathEvent e)
    160.     {
    161.         Player p= e.getEntity();
    162.         if(spieler.contains(p))
    163.         {
    164.             this.removePvP(p);
    165.         }
    166.     }
    167. }
    168.   //Wenn ihr Teile oder den ganzen Code haben wollt: bedient euch ;)
    169.    
    Ich habe nach einiger Recherche das Problem gelöst und wollte meine Lösung hier posten, damit niemand anderes noch an dieser Exception verzweifelt.


    1. Wann tritt sie auf

    Eine ConcurrentModificationException tritt auf, wenn von zwei verschiedenen Threads auf eine Liste zugegriffen wird, oder wenn während der Iteration (Durchgehen aller Objekte einer Liste), ein Objekt entfernt werden könnte.


    2. Wie löst man es "richtig"

    Falls es sich hierbei um einen Multi-Thread Umgebung handelt, könnt diese Klasse helfen:
    http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html


    Bei einer Single-Thread Umgebung empfehlt sich eine Lösung mit lokaler Variable, die mit der "for"-Schleife Iteriert wird (oder mit Iteratoren, wie man das halt lieber macht):
    Code (Text):
    1. for(Integer i : new ArrayList<Integer>(timeout))//by MiCrJonas1997
    Hier noch ein Link der von @manf gepostet wurde, bezüglich weiterer Möglichkeiten:
    http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html

    Ich hoffe ich konnte dem ein oder anderen helfen ;)

    MfG
    _Baum_
     
    #1
  2. MiCrJonas
    Offline

    MiCrJonas

    Registriert seit:
    29. Oktober 2012
    Beiträge:
    1.069
    Code (Text):
    1. for(Integer i : new ArrayList<Integer>(timeout))
    Du gehst die Liste an einer Stelle durch und löschst dabei eventuell Einträge. Das geht nicht. Probier mal meinen Code aus. Da wird nicht die gleiche Liste durchlaufen, in der auch die Elemente gelöscht werden.
     
    #2
    games6471 gefällt das.
  3. xMyPhatex
    Offline

    xMyPhatex

    Registriert seit:
    25. August 2014
    Beiträge:
    7
    Minecraft:
    xMyPhatex
    @MiCrJonas1997:
    Er hat die Lösung bereits gefunden und wollte diese mit uns teilen. =)

    @_Baum_:
    Ähnliche Probleme habe ich meist mit laufenden Liste wie OnlinePlayers oder OfflinePlayers. Daher packe, sollte ich zwingend eine Liste verwenden müssen, diese nochmal in eine lokale Variable. Gerade dann wenn die Ausführungen in den Schleifen größer sind.
     
    #3
  4. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    Ach so einfach wärs gewesen xD

    Naja wenigstens kann ich jetzt Maps benutzen ;)
     
    #4
  5. MiCrJonas
    Offline

    MiCrJonas

    Registriert seit:
    29. Oktober 2012
    Beiträge:
    1.069
    Das ganze hat absolut nichts mit Threads/Threadsicherheit zu tun. Dein ganzer Code wird im selben Thread ausgeführt. Das Problem ist, dass du mit einem Iterator (benutzt von deiner erweiterten for-Schleife) die Einträge der Liste durchgehst und während du die Liste durchgehst, versuchst du schon Einträge zu löschen. Wie gesagt, das geht nicht. Bei dem Beispiel von mir wird eine Kopie der Liste durchgegangen, weshalb du die originale Liste bearbeiten kannst bzw. Einträge löschen kannst.
     
    #5
  6. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    *EDIT* Habe keine Ahnung hiervon, weiß nicht, ob das stimmt

    @MiCrJonas1997

    Nur das es eine Klasse ist, heißt es nicht, dass es alles im gleichen Thread abläuft!
    http://wiki.bukkit.org/Scheduler_Programming/de

    Der TaskScheduler macht GENAU das: er registriert neue Threads, die bestimmte Aufgaben ausführen!

    Auch Swing Timer laufen unabhängig vom Main Thread in einem asynchronen Thread:
    http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
    Zitat daraus:
    Und auch Bukkit-Events laufen in einem separaten Thread: die synchronen in einem synchronen und die asynchronen in einem asynchronen.

    Korrigiere mich, wenn ich mich täusche

    MfG
    _Baum_
     
    #6
  7. MiCrJonas
    Offline

    MiCrJonas

    Registriert seit:
    29. Oktober 2012
    Beiträge:
    1.069
    Zur gleichen Zeit wird (Ja, Threads laufen [in Bukkit] nie gleichzeitig) nicht aus 2 Threads auf die Variablen zugegriffen, weil alles von
    "TaktImpuls()" (Methoden klein *hust*) ausgeht, und danach kein neuer Thread gestartet wird. Die anderen Zugriffe geschehen viel früher.
     
    #7
  8. #8
    games6471 und MiCrJonas gefällt das.
  9. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    *EDIT* Gequirlte Scheiße: einfach nicht lesen

    Threads laufen in Bukkit nie gleichzeitig? Die Aufteilung in Haupt- und Nebenthreads basiert ja auf dem Fakt, dass der Main-Thread nicht angehalten werden darf, also durchgehend läuft. Heißt das nicht automatisch, dass ab und zu mehrere Thread gleichzeitig laufen müssen?

    @manf
    Nun ja, nehmen wir mal an, dass der Event Threat und der Synchrone Thread des Tasks gleichzeitig laufen.
    Dann wäre der Grund:
    Und die Lösung (aus http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html):
    Meine Annahme, dass mein Plugin mehrere Threads nutz beruht auf diesem Artikel: http://wiki.bukkit.org/Scheduler_Programming/de

    Thread 1: Haupthread
    Thread 2: Event- Thread
    Thread 3: SyncRepeatingTask - Thread

    MfG
    _Baum_
     
    #9
  10. Das ist für das Problem irrelevant. Dafür braucht man keine Bukkit Dokumentation, sonder "Common Sense" und eine Ahnung von der Materie (Java).
     
    #10
    games6471 und MiCrJonas gefällt das.
  11. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    Na gut ^^
    Haupsache das Problem ist gelöst, danke für eure Mithilfe :D
    Ich arbeite erst seit einem Jahr mit Java, davon der Großteil in der Schule, da habe ich noch nicht das perfekte Fingerspitzengefühl, was solche Sachen betrifft ;)
     
    #11
  12. _Baum_
    Offline

    _Baum_

    Registriert seit:
    4. August 2013
    Beiträge:
    66
    Minecraft:
    PlueschAffe
    *EDIT*
    Halbwissen ist schlimmer als Unwissen -.-

    Code (Text):
    1. [14:52:47] [Server thread/WARN]: [ScorpionPvP] Task #7 for ScorpionPvP v1.0 generated an exception
    2. java.util.ConcurrentModificationException
    Daraufhin hatte ich das dringende Bedürfnis in meine Tastatur zu beißen...

    Eigener Thread zu diesem Thema folgt...

    @MiCrJonas1997 nehme jetzt deine Lösung, nochmal danke dafür :)
    Code (Text):
    1. public class AntiLogout implements Listener{
    2.  
    3.     private HashMap<Player,Integer> liste;
    4.  
    5.     private MainFixes main;
    6.     private String prefix;
    7.  
    8.     private Farben farben;
    9.  
    10.     public AntiLogout(MainFixes m)
    11.     {
    12.         liste= new HashMap<Player,Integer>();
    13.         m.getServer().getScheduler().scheduleSyncRepeatingTask(m, new Runnable() {
    14.  
    15.             public void run() {
    16.             taktImpuls();
    17.             }
    18.             }, 60L, 20L);
    19.         main=m;
    20.         prefix= main.getPrefix();
    21.         farben= main.getFarben();
    22.     }
    23.  
    24.     protected void taktImpuls() //Methode zu Feier des Tages klein ^^
    25.     {
    26.         HashMap<Player,Integer> liste1= new HashMap<Player,Integer>(this.liste);
    27.         if(!liste.isEmpty())
    28.         {
    29.             for(Iterator<Player> it=liste1.keySet().iterator();it.hasNext();)
    30.             {
    31.                 Player p= it.next();
    32.                 int i= liste1.get(p);
    33.                 if(i<=0)
    34.                 {
    35.                     liste1=removePvP(p,liste1);
    36.                     this.liste=liste1;
    37.                     return;
    38.                 }
    39.                 else
    40.                 {
    41.                     liste1.put(p, i-1);
    42.                 }
    43.             }
    44.             this.liste=liste1;
    45.         }
    46.     }
    47.  
    48.     public void addPvP(Player p)
    49.     {
    50.         HashMap<Player,Integer> liste1= new HashMap<Player,Integer>(this.liste);//Auf Nummer sicher gehen
    51.         if(liste1.containsKey(p))
    52.         {
    53.             liste1.put(p, 8);
    54.             BarAPI.removeBar(p);
    55.         }
    56.         else
    57.         {
    58.            liste1.put(p, 8);
    59.            BarAPI.setMessage(p, "§4§l*PvP*", 8);
    60.         }
    61.     this.liste=liste1;
    62.     }
    63.  
    64.     public HashMap<Player,Integer> removePvP(Player p,HashMap<Player,Integer> liste1)
    65.     {
    66.         if(liste1.containsKey(p))
    67.         {
    68.             liste1.remove(p);
    69.             p.sendMessage(prefix+"§2*Du bist nicht mehr im PvP-Modus*");
    70.             BarAPI.removeBar(p);
    71.             if(main.hatSchutz(p))
    72.             {
    73.                 farben.gruenFaerben(p);
    74.             }
    75.             else
    76.             {
    77.                 farben.entfaerben(p);
    78.             }
    79.         }
    80.         return liste1;
    81.     }
    82.  
    83.     //Events
    84.     @EventHandler
    85.     public void onPlayerLeave(PlayerQuitEvent e)
    86.     {
    87.         Player p=e.getPlayer();
    88.         if(liste.containsKey(p))
    89.         {
    90.             if(main.check(p.getLocation()))
    91.             {
    92.                 p.setHealth(0.0);
    93.             }
    94.             liste=removePvP(p,liste);
    95.         }
    96.     }
    97.  
    98.     @SuppressWarnings("deprecation")
    99.     @EventHandler
    100.     public void interaktionPvP(EntityDamageByEntityEvent e)
    101.     {
    102.         if(e.getEntity() instanceof Player)
    103.         {
    104.             Player angreifer;
    105.             Player opfer= (Player) e.getEntity();
    106.             Entity damager= e.getDamager();
    107.             if(damager instanceof Projectile)
    108.             {
    109.                 damager=((Projectile) damager).getShooter();
    110.             }
    111.             if(damager instanceof Player)
    112.             {
    113.                 angreifer = (Player) damager;
    114.             }
    115.             else
    116.             {
    117.                 return;
    118.             }
    119.             if(angreifer.equals(opfer))
    120.             {
    121.                 return;
    122.             }
    123.             if(main.istHauptwelt(opfer.getWorld().getName()))
    124.             {
    125.                 if(main.check(angreifer.getLocation())&&main.check(opfer.getLocation())&&!main.hatSchutz(opfer)&&!main.hatSchutz(angreifer))
    126.                 {
    127.                     addPvP(angreifer);
    128.                     addPvP(opfer);
    129.                 }
    130.             }
    131.             else
    132.             {
    133.                 if(main.check(angreifer.getLocation())&&main.check(opfer.getLocation()))
    134.                 {
    135.                     addPvP(angreifer);
    136.                     addPvP(opfer);
    137.                 }
    138.             }
    139.         }
    140.     }
    141.  
    142.  
    143.     @EventHandler
    144.     public void onDeath(PlayerDeathEvent e)
    145.     {
    146.         Player p= e.getEntity();
    147.         if(liste.containsKey(p))
    148.         {
    149.             liste=removePvP(p,liste);
    150.         }
    151.     }
    152. }
    Hiezu noch eine letzte Frage: Kann das "inteaktionPvP" Event ausgeführt werden, währed die Iteration im "taktImpuls" abläuft?
    Dann müsste ich den Code ein wenig umstellen...

    Das wär dann auch die letzte Sache in diesem Thread (obwohl sie nicht zum Rest passt), danke im voraus!

    MfG

    _Baum_
     
    #12