Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-461

getOfflinePlayer(String) is blocking yet not thread-safe

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • None
    • None

      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)
      

            md_5 md_5
            Byteflux Matt Harris
            Votes:
            4 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: