[SPIGOT-461] getOfflinePlayer(String) is blocking yet not thread-safe Created: 22/Jan/15  Updated: 07/Jun/15  Resolved: 07/Jun/15

Status: Resolved
Project: Spigot
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Matt Harris Assignee: md_5
Resolution: Fixed Votes: 4
Labels: craftbukkit

Issue Links:
Duplicate
is duplicated by SPIGOT-914 Failed to handle packet ConcurrentMod... Closed

 Description   

Spoke to md_5 on IRC about getOfflinePlayer(String) not being thread-safe. If a method is blocking, it is supposed to be thread-safe otherwise he says it is considered to be a bug.

I wrote a simple plugin to observe failed attempts to invoke getOfflinePlayer() from multiple async tasks:

GetOfflinePlayerAsyncTest.java
package net.minelink.gopat;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

public class GetOfflinePlayerAsyncTest extends JavaPlugin {

    @Override
    public boolean onCommand(final CommandSender sender, Command command, String label, String[] args) {
        for (int i = 0; i < 3; ++i) {
            Bukkit.getScheduler().runTaskLaterAsynchronously(this, new Runnable() {
                @Override
                public void run() {
                    Bukkit.getOfflinePlayer(UUID.randomUUID().toString().substring(0, 15));
                }
            }, 1);
        }
        return true;
    }

}

Invoking the above code will produce one of three outcomes:

  • It will simply work
  • It will throw a ConcurrentModificationException
  • It will throw a NullPointerException

The stack traces observed in the console are as follows:

ConcurrentModificationException

[23:55:17 WARN]: Exception in thread "Craft Scheduler Thread - 0"
[23:55:17 WARN]: org.apache.commons.lang.UnhandledException: Plugin GetOfflinePlayerAsyncTest v0.0.1-SNAPSHOT generated an exception while executing task 28
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.ConcurrentModificationException
        at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
        at java.util.LinkedList$ListItr.next(LinkedList.java:886)
        at com.google.common.collect.Iterators$9.next(Iterators.java:939)
        at com.google.common.collect.Iterators.addAll(Iterators.java:357)
        at com.google.common.collect.Lists.newArrayList(Lists.java:147)
        at net.minecraft.server.v1_8_R1.UserCache.a(UserCache.java:213)
        at net.minecraft.server.v1_8_R1.UserCache.c(UserCache.java:194)
        at net.minecraft.server.v1_8_R1.UserCache.getProfile(UserCache.java:123)
        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.getOfflinePlayer(CraftServer.java:1288)
        at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741)
        at net.minelink.gopat.GetOfflinePlayerAsyncTest$1.run(GetOfflinePlayerAsyncTest.java:19)
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftTask.run(CraftTask.java:71)
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)

NullPointerException

[23:55:22 WARN]: Exception in thread "Craft Scheduler Thread - 3"
[23:55:22 WARN]: org.apache.commons.lang.UnhandledException: Plugin GetOfflinePlayerAsyncTest v0.0.1-SNAPSHOT generated an exception while executing task 35
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
        at java.util.LinkedList$ListItr.next(LinkedList.java:891)
        at com.google.common.collect.Iterators$9.next(Iterators.java:939)
        at com.google.common.collect.Iterators.addAll(Iterators.java:357)
        at com.google.common.collect.Lists.newArrayList(Lists.java:147)
        at net.minecraft.server.v1_8_R1.UserCache.a(UserCache.java:213)
        at net.minecraft.server.v1_8_R1.UserCache.c(UserCache.java:194)
        at net.minecraft.server.v1_8_R1.UserCache.getProfile(UserCache.java:123)
        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.getOfflinePlayer(CraftServer.java:1288)
        at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741)
        at net.minelink.gopat.GetOfflinePlayerAsyncTest$1.run(GetOfflinePlayerAsyncTest.java:19)
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftTask.run(CraftTask.java:71)
        at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)


 Comments   
Comment by mibby mibster [ 26/May/15 ]

Any update to this? Still an on-going issue with 1.8.6.

Spigot 1.8.6 git-Spigot-6a6b839-b0e81a4
ChestShop v3.8.8

[23:10:18] [Server thread/INFO]: [ChestShop] Enabling ChestShop v3.8.8
[23:10:18] [Server thread/ERROR]: Error occurred while enabling ChestShop v3.8.8 (Is it up to date?)
java.util.ConcurrentModificationException
	at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_45]
	at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_45]
	at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.UserCache.a(UserCache.java:235) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.UserCache.c(UserCache.java:216) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.UserCache.getProfile(UserCache.java:152) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at com.Acrobot.ChestShop.UUIDs.NameManager.load(NameManager.java:234) ~[?:?]
	at com.Acrobot.ChestShop.ChestShop.onEnable(ChestShop.java:95) ~[?:?]
	at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugin(CraftServer.java:356) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.enablePlugins(CraftServer.java:316) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.MinecraftServer.s(MinecraftServer.java:418) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.MinecraftServer.k(MinecraftServer.java:382) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.MinecraftServer.a(MinecraftServer.java:337) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.DedicatedServer.init(DedicatedServer.java:256) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:528) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_45]

Also occasionally occurs with EnjinMinecraftPlugin v2.7.2 at startup.

[19:30:44] [Server thread/WARN]: [EnjinMinecraftPlugin] Task #79 for EnjinMinecraftPlugin v2.7.2-bukkit generated an exception
java.util.ConcurrentModificationException
	at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_40]
	at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_40]
	at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.UserCache.a(UserCache.java:243) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.UserCache.c(UserCache.java:224) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.UserCache.getProfile(UserCache.java:153) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at org.bukkit.craftbukkit.v1_8_R2.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at com.enjin.officialplugin.EnjinMinecraftPlugin$1.run(EnjinMinecraftPlugin.java:862) ~[?:?]
	at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftTask.run(CraftTask.java:71) ~[spigot.jar:git-Spigot-c136710-350cb99]
	at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:350) [spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.MinecraftServer.A(MinecraftServer.java:718) [spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.DedicatedServer.A(DedicatedServer.java:368) [spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.MinecraftServer.z(MinecraftServer.java:651) [spigot.jar:git-Spigot-c136710-350cb99]
	at net.minecraft.server.v1_8_R2.MinecraftServer.run(MinecraftServer.java:554) [spigot.jar:git-Spigot-c136710-350cb99]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_40]
Comment by mibby mibster [ 14/Mar/15 ]

Would very much greatly appreciate getOfflinePlayer check becoming async and thread safe to prevent ConcurrentModificationExceptions on server startup.

As I'm still experiencing this issue myself with Spigot 1.8.3 (git-Spigot-ea179b3-6e0120a) and ChestShops 3.8.5.
https://hub.spigotmc.org/jira/browse/SPIGOT-646

Comment by mibby mibster [ 09/Mar/15 ]

Any update to making this thread-safe?

https://hub.spigotmc.org/jira/browse/SPIGOT-646

Generated at Mon Apr 21 21:46:24 UTC 2025 using Jira 10.3.5#10030005-sha1:190c783f2bd6c69cd5accdb70f97e48812a78d14.