Paul Reiners
Paul Reiners

Reputation: 7896

java.util.concurrent.Future.get() not returning

I have the following Java code:

final Future future = exeService.submit(
    new Runnable() {
        public void run() {
            myObject.doSomething();
        }
    }
);

future.get();

where exeService is an instance of

java.util.concurrent.ExecutorService

The problem is that myObject.doSomething() never returns, and, hence, future.get() never returns.

However, if I replace the call to submit with a call to execute like this:

exeService.execute(
    new Runnable() {
        public void run() {
            myObject.doSomething();
        }
    }
);

the call to myObject.doSomething() does return. I don't know if it matters, but doSomething() is a void method.

Why is doSomething() finishing when using execute but not when using submit?

Also, I don't need to use Future.get(); that just seemed to be the most natural way of doing this. (I also run into the same problem with CountdownLatch.) The point is that I need to wait for doSomething() to finish before proceeding, and, for complicated reasons I won't go into here, I need to launch it on a separate thread. If there is another way of doing this that works, that would be fine.

Upvotes: 6

Views: 28752

Answers (5)

Shilpa Dolai
Shilpa Dolai

Reputation: 11

There are multiple things going wrong here:

  1. When you execute future.get(), by that time it was not done executing hence returns nothing. and when it does actually finish, you never go back and ask for the result. So doSomething does return but you never check back in for the result.

  2. Also it does matter that doSomething is returning nothing. There is nothing to be be fatched using future.get().

  3. Even if the method returned something, it would have still printed null because the result of the method is ignored because you are using runnable. You need to use callable for it to keep the result of the method.

  4. By any chance If you really need to wait till you get the result before you move on to the next line, rather than doing future.get without knowing if the computation is done, we can do below

     Integer res = executorService.submit(
             myObject::doSomething
     ).get();
     System.out.println(res);
     executorService.shutdown();
    

Here I am assuming doSomething returns an int.

The difference between doing future.get and above is, in the former one you make a future object and move on, then try to fetch the results which are not ready yet. Here you dont move on till the results are ready and are stored in the Integer variable.

Upvotes: 0

anish
anish

Reputation: 7412

Java futures are blocking! get(). This method blocks the current thread until a future instance completes its work, thus requiring the use of one thread more than the work that must be performed just to manage what happens when it is done

Upvotes: 2

Alexander Pogrebnyak
Alexander Pogrebnyak

Reputation: 45576

Check for a deadlock(s) in doSomething.

I would start with searching for wait calls.

If you wait for something, you need to signal the object you are waiting for from the other thread by calling notify or notifyAll.

Upvotes: 0

BalusC
BalusC

Reputation: 1108712

I created an SSCCE:

package com.stackoverflow.q2585971;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {

    public static void main(String args[]) throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();
        Future<?> future = executor.submit(
            new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println("Epic fail.");
                    }
                }
            }
        );

        System.out.println("Waiting for task to finish..");
        future.get();
        System.out.println("Task finished!");
        executor.shutdown();
    }

}

It works perfectly fine. It first prints

Waiting for task to finish..

then after one second you see

Task finished!

So, your problem lies somewhere else. I'll duplicate my comment on your question here:

Your question is pretty confusing. The first construct should just work. The confusion is in "returning". Don't you just mean "finishing" or "executing"? Your confusion seems to be based on the fact that future.get() actually waits for the runnable to be finished and thus will block the thread and prevent it from executing the remnant of the code after the future.get() line.

Upvotes: 8

pajton
pajton

Reputation: 16226

As in Executor.execute() Javadoc:

Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

So, the method execute() returns immediately leaving you with no option to query to status of submitted task.

On the other hand ExecutorService.submit():

Submits a Runnable task for execution and returns a Future representing that task. The Future's get method will return null upon successful completion.

The Future.get() will return only after successful competion, so never in your case.

This is further noted in Future.get() documentation:

Waits if necessary for the computation to complete, and then retrieves its result.

Upvotes: 18

Related Questions