java.lang.IllegalAccessError

Discussion in 'Plugin Development' started by escortkeel, Jun 20, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    escortkeel

    Hi!

    One of my plugin's users has managed to find a very obscure multi-threading related bug. Multi-threading is required in the plugin because it receives instructions over TCP/IP and must respond to them promptly and accordingly.

    The bug causes the following stack trace to be printed to the console:

    Code:
    [WARNING] Could not properly handle event BLOCK_PHYSICS:
    java.lang.IllegalAccessError: Synchronized code got accessed from another thread: me.escortkeel.remotebukkit.ConnectionHandler
    at org.bukkit.event.Listener.onBlockPhysics(Listener:0)
    at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:302)
    at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62)
    at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:477)
    at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:462)
    at net.minecraft.server.World.k(World.java:510)
    at net.minecraft.server.World.applyPhysics(World.java:496)
    at net.minecraft.server.World.update(World.java:459)
    at net.minecraft.server.World.setTypeId(World.java:434)
    at org.bukkit.craftbukkit.block.CraftBlock.setTypeId(CraftBlock.java:92)
    at org.bukkit.craftbukkit.block.CraftBlock.setType(CraftBlock.java:88)
    at com.tommytony.war.volume.Volume.resetBlocks(Volume.java:270)
    at com.tommytony.war.War.unloadWar(War.java:278)
    at com.tommytony.war.War.onDisable(War.java:118)
    at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:217)
    at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:363)
    at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:400)
    at me.ryanclancy000.plugman.PlugManCommands.reloadPlugin(PlugManCommands.java:419)
    at me.ryanclancy000.plugman.PlugMan.doCommand(PlugMan.java:145)
    at me.ryanclancy000.plugman.PlugMan.onCommand(PlugMan.java:34)
    at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40)
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:166)
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:480)
    at me.escortkeel.remotebukkit.ConnectionHandler.run(ConnectionHandler.java:61)
    2012-06-18 17:44:59 [INFO] This error is logged only once: it could have occurred multiple times by now.
    2012-06-18 17:44:59 [INFO] Please contact one of the authors of plugin 'RemoteBukkit': Keeley Hoek (escortkeel)
    While I am aware that this error is thrown by the JVM when compiled code attempts to perform an illegal operation that the compiler would normally catch, I don't understand exactly what, in this instance, is illegal about my thread dispatching a command a console.

    Thanks in advance,
    Keeley :)
     
  2. To me, the stack-trace looks like you are trying to dispatch a command from a separate thread, and that command changes a block.

    It's not safe to do that. In fact, almost nothing you can do with the minecraft server / bukkit API is thread-safe.
    What is happening here is you execute the command from the separate thread, which calls some command handler, which sets a block type somewhere, which triggers some block updates, which fire the BlockPhysicsEvent.
    ALL that happens on your different thread. I hope you understand the severity of the issues that rise from that.

    What you need to do to safely access anything useful of the bukkit API (with a couple of exceptions) is create some sort of "operation queuing" system that is synchronized. Your TCP thread receives something that should be done and it appends an executor (Runnable, Callable, whatever you need) to a queue type of thing (for example a LinkedList, make sure you synchronize it properly).
    Then, you have a sync repeating task running (using the BukkitScheduler) every 1 or 2 ticks (maybe even less frequently, if operations don't occur that frequently and it's not a problem that they might be delayed by half a second or so).
    That task polls your operation queue and executes the operations (remember, you are now on the main thread, so you may do that now).

    You probably need to retrieve results in your TCP thread, so I'd use Callables and make your thread block until the operation has been performed. That's also explained on the wiki page by the way.
     
  3. Offline

    escortkeel

    Thanks so much Bone008!

    You really shed light on the problem. Really appreciate it!. :D

    Thanks,
    Keeley
     
  4. Oh, actually, when I think about it again. My suggestion is complete bullshit :D
    That would be the solution you'd have to take if the scheduler didn't exist (like in any other normal Java program). But that queuing system is actually exactly what the scheduler does for you.

    So, all you have to do is schedule a task or call a sync method with the scheduler, that's wayyy simpler.

    The simplest case: You just want some MC method to be called. The scheduler itself is thread-safe, so you can do (in your custom thread):

    Code:
    Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(new Runnable(){
        @Override
        public void run(){
            someUnsafeBukkitMethod();
        }
    });
    The scheduler will take care of anything else and execute your Runnable at the next server tick.
     
  5. I have recently designed an class to make the comunucation between the ukkit thread and its own thread easier by an kind of task dispatch system thingy, like the SwingWorker class
     
  6. Offline

    escortkeel

    Hahaha :D. Thanks for the new Suggestion! :p

    ~Keeley
     
  7. look inside my signature for a other way to combine networking (blocking taskt) whit tasks that invoke bukkit (sending messaging to players, using other world methodes) whitout causing thread problems
     
Thread Status:
Not open for further replies.

Share This Page