Solved FutureTask.get() blocks with BukkitScheduler

Discussion in 'Plugin Development' started by Austy, Apr 23, 2013.

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

    Austy

    Code:
    Callable<String> task = new Callable<String>() {
        @Override
        public String call() {
            return "okay";
        }
    };
    FutureTask<String> ft = new FutureTask<String>(task);
    Bukkit.getScheduler().runTask(this, ft);
    try {
        System.out.println(ft.get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    I'm trying to schedule a FutureTask, but it blocks on get(), even if call() simply returns a string. When I try to schedule it without using the BukkitScheduler API, everything works properly. Any ideas how to solve this?
     
  2. Offline

    skore87

    Have you tried the "done()" method yet to verify that it has completed yet? Since we're working with bukkit, everything is in ticks, so it would be slower than normal.
     
  3. Offline

    Austy

    I don't need to check if it's done. I can wait for it to complete. And as You can see it simply returns a string, so it shouldn't block so long.
     
  4. Offline

    skore87

    Yeah, but bukkit runs on ticks. Every 1/20th second (approx.) it will run tasks, and in your case it will start it after 1 tick meaning you don't have a return value yet.
     
  5. Offline

    Comphenix

    There's a simple reason for why get() is blocking - the main thread is waiting for itself.

    The scheduler will run a synchronous task (runTask) on the main thread during the same tick, but right after the current method finishes (onCommand(), onEnable(), a task, etc.). The problem here is that you're blocking the main thread with get(), which locks it in the current method, and the scheduler never gets a chance to run the task you scheduled. This is called a deadlock.

    The only solution is to not call get() in the first place. If you need to process a value after it has been computed, you should schedule a new task inside current task instead. Also, if this task is blocking, remember to schedule it asynchronously:
    Code:java
    1. public class ExampleMod extends JavaPlugin {
    2. @Override
    3. public void onEnable() {
    4. getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
    5. @Override
    6. public void run() {
    7. final String value = "VALUE";
    8.  
    9. // Get the value - for instance by retrieving it from an MySQL server
    10. try {
    11. Thread.sleep(1000);
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15.  
    16. getServer().getScheduler().runTask(ExampleMod.this, new Runnable() {
    17. @Override
    18. public void run() {
    19. // Display it
    20. getServer().broadcastMessage(value);
    21. }
    22. });
    23. }
    24. });
    25. }
    26. }
     
    Austy likes this.
  6. Offline

    Austy

    Comphenix, thank You. I didn't know the BukkitSchedulder works that way. Oh, and there's a note to callSynchMethod(), that get() shouldn't be called from the main server thread. I didn't notice it before, because I wanted to run this task asynchronously (I used runTask() instead of runTaskAsynchronously() in code from this thread, because it didn't work as well). Well, I'm going to have to schedule this task with the Executor, because I really need to call get().
     
  7. Offline

    Comphenix

    You only need to call it if you absolutely must block the main thread. Otherwise, you can just as easily schedule a new task inside the first one, like in my previous example.

    You really gain nothing by calling get() if all you're doing is scheduling a task on a single thread. You might as well do the work in the main thread in that case.
     
  8. Offline

    Austy

    Comphenix, I'm trying to run some asynchronous computations early, so they don't block for long when I call get() in the main thread. I also store Future objects in a map, so they indicate running computations for their keys.
     
Thread Status:
Not open for further replies.

Share This Page