1.8.8 Why java.util.ConcurrentModificationException ?

Discussion in 'Spigot Plugin Development' started by GabrielBlink, Feb 16, 2020.

Thread Status:
Not open for further replies.
  1. Hello Spigot Developers,
    I'm trying to make a AFK Kicker in my server but an "java.util.ConcurrentModificationException" is occourring, i want to know why

    Error:
    Code (Java):
    16.02 13:42:46 [Server] WARN [AtlasAntiAFK] Task #72 for AtlasAntiAFK v1.7 generated an exception
    16.02 13:42:46 [Server] INFO java.util.ConcurrentModificationException
    16.02 13:42:46 [Server] INFO at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445) ~[?:1.8.0_212]
    16.02 13:42:46 [Server] INFO at java.util.HashMap$KeyIterator.next(HashMap.java:1469) ~[?:1.8.0_212]
    16.02 13:42:46 [Server] INFO at com.atlasplugins.antiafk.runnables.AFKTimer$2.run(AFKTimer.java:69) ~[?:?]
    16.02 13:42:46 [Server] INFO at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:71) ~[server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:350) [server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:723) [server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) [server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [server.jar:git-Spigot-db6de12-18fbb24]
    16.02 13:42:46 [Server] INFO at java.lang.Thread.run(Thread.java:748) [?:1.8.0_212]
    MyCode (AFKTimer.java):
    Code (Text):
    package com.atlasplugins.antiafk.runnables;


    import java.util.HashMap;
    import java.util.Iterator;

    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    import org.bukkit.scheduler.BukkitRunnable;

    import com.atlasplugins.antiafk.Main;
    import com.atlasplugins.antiafk.apis.TitleAPI;
    import com.atlasplugins.antiafk.objects.AtlasAFKPlayer;

    public class AFKTimer {

        public static String messageKick;
        public static HashMap<String,AtlasAFKPlayer> lastPostions = new HashMap<String,AtlasAFKPlayer>();
        public static int AFK_TIMER;
        public static int AFK_KICKER;
        public static int AFK_TIME;
       
        public static void start() {
            AFK_TIME = Main.getInstance().getConfig().getInt("TimeToKick");
            messageKick = "";
            for(String s : Main.getInstance().getConfig().getStringList("KickMessage")) {
                if(!messageKick.isEmpty()) {
                    messageKick = messageKick+"\n§r"+ChatColor.translateAlternateColorCodes('&', s);
                }else {
                    messageKick = ChatColor.translateAlternateColorCodes('&', s);
                }
            }
            Bukkit.getScheduler().cancelTask(AFK_TIMER);
            Bukkit.getScheduler().cancelTask(AFK_KICKER);
            AFK_TIMER = new BukkitRunnable() {
               
                @Override
                public void run() {
                    synchronized(lastPostions) {
                        for(Player online : Bukkit.getOnlinePlayers()) {
                            if(!online.hasPermission("atlasantiafk.bypass") && !online.isOp()) {
                                if(lastPostions.containsKey(online.getName())) {
                                    if(online.getLocation().getDirection().equals(lastPostions.get(online.getName()).getLastVector())) {
                                        if(!lastPostions.get(online.getName()).isAfk()) {
                                            lastPostions.get(online.getName()).setAfkMillis(System.currentTimeMillis());
                                        lastPostions.get(online.getName()).setAfk(true);
                                        }
                                    }else {
                                        lastPostions.remove(online.getName());
                                    }
                                }else {
                                    AtlasAFKPlayer afkPlayer = new AtlasAFKPlayer(online, false);
                                    afkPlayer.setLastVector(online.getLocation().getDirection());
                                    lastPostions.put(online.getName(), afkPlayer);
                                }
                            }
                        }
                    }
                }
            }.runTaskTimerAsynchronously(Main.getPlugin(Main.class), 20L*10, 20l*60*2+20l*30).getTaskId();
           
            AFK_KICKER = new BukkitRunnable() {
                @Override
                public void run() {
                    synchronized(lastPostions) {
                        Iterator<String> i = lastPostions.keySet().iterator();
                        while(i.hasNext()) {
                            String playerName = i.next();
                            if(Bukkit.getPlayer(playerName) !=null && lastPostions.containsKey(playerName)) {
                                Player p = Bukkit.getPlayer(playerName);
                                if(!p.hasPermission("atlasantiafk.bypass") && !p.isOp()) {
                                    if(lastPostions.containsKey(p.getName())) {
                                    if(lastPostions.get(p.getName()).isAfk()) {
                                        long startTime = lastPostions.get(p.getName()).getAfkMillis();
                                        long a = System.currentTimeMillis() - startTime;
                                        long seconds = a/1000;
                                        long b = AFK_TIME-seconds;
                                        if(AFK_TIME > seconds) {
                                            TitleAPI.sendFullTitle(p, 5, 1000, 5, "§e§lVocê está AFK", "§f§lEnviando você para o Lobby em §c§l"+getFormated(b));
                                        }else {
                                            String server_selected = Main.getRandomServer();
                                            TitleAPI.clearTitle(p);
                                            if(!server_selected.equalsIgnoreCase("NENHUM-ONLINE")) {
                                                Main.enviarPlayer(p, server_selected,true);
                                            }else {
                                                p.kickPlayer(messageKick);
                                            }
                                        }
                                }
                                    }
                            }
                            }else {
                                i.remove();
                            }
                        }
                    }
                }
            }.runTaskTimer(Main.getPlugin(Main.class), 20L*10, 20L).getTaskId();
        }
        public static String getFormated(long totalSecs) {
            long minutes = (totalSecs % 3600) / 60;
            long seconds = totalSecs % 60;
            if(seconds < 10) {
                String formated = ""+minutes+":0"+seconds;
                return formated;
            }else {
            String formated = ""+minutes+":"+seconds;
            return formated;
            }
            }
    }
     
     
    • Optimistic Optimistic x 1
  2. You can not modify a collection while iterating over it.
    Btw, what is line 69 of the code?
     
    • Agree Agree x 1
  3. Can you show line 69?
     
  4. As @robertlit said, you can't modify a collection while iterating over it.
    AFK_TIMER is adding/removing objects to lastPositions while AFK_KICKER is looping through it.
     
  5. Bur why would .next() specifically throw it, not the add or remove? Try just lastPositions.forEach.
     
  6. Because he's trying to iterate keys, but changing map itself.
    Or iterate Map.Entry of lastPostions map.
     
  7. SteelPhoenix

    Moderator

    You have two tasks modifying the map no? #next() also checks if it was modified.

    Also, can we talk about all the static abuse
     
Thread Status:
Not open for further replies.