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; } } }
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.
Because he's trying to iterate keys, but changing map itself. Or iterate Map.Entry of lastPostions map.
You have two tasks modifying the map no? #next() also checks if it was modified. Also, can we talk about all the static abuse