Returning a value from Runnable
Asked Answered
E

8

72

The run method of Runnable has return type void and cannot return a value. I wonder however if there is any workaround of this.

I have a method like this:

public class Endpoint {
    public method() {
       Runnable runcls = new RunnableClass();
       runcls.run()
    }
}

The method run is like this:

public class RunnableClass implements Runnable {
    
    public JaxbResponse response;

    public void run() {
        int id = inputProxy.input(chain);
        response = outputProxy.input();
    }
}

I want to have access to response variable in method. Is this possible?

Eger answered 3/12, 2012 at 13:39 Comment(2)
Where did the response come from? Or better yet, the outputProxy ?Rathskeller
those methods are in diffrent classes, i should edit my question, sorry for confuse you.Eger
H
92

Use Callable<V> instead of using Runnable interface.

Example:

public static void main(String args[]) throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(3);
    Set<Future<Integer>> set = new HashSet<>();

    for (String word : args) {
      Callable<Integer> callable = new WordLengthCallable(word);
      Future<Integer> future = pool.submit(callable);
      set.add(future);
    }

    int sum = 0;
    for (Future<Integer> future : set) {
      sum += future.get();
    }

    System.out.printf("The sum of lengths is %s%n", sum);
    System.exit(sum);
}

In this example, you will also need to implement the class WordLengthCallable, which implements the Callable interface.

Hoecake answered 3/12, 2012 at 13:42 Comment(5)
Exception in thread "main" java.lang.Error: Unresolved compilation problem: WordLengthCallable cannot be resolved to a type. I'm not smart enough to fix it but it doesn't work for me.Miles
Also I think new HashSet<Future,Integer>>() should be new HashSet<Future<Integer>>()Miles
@Miles it is just a concrete implementation of Callable Interface. For more on Callable: blogs.oracle.com/CoreJavaTechTips/entry/get_netbeans_6Hoecake
If your delegate doesn't throw any exceptions, it's better to use Supplier<T>.Owens
Thanks, Narendra Pathai. However, I have a problem. The .join is blocking my UI, negating all benefits of the separate thread. How could I prevent this?Labuan
S
18
public void check() {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Integer> result = executor.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            return 10;
        }
    });

    try {
        int returnValue = result.get();
    } catch (Exception exception) {
       //handle exception
    }
}
Sulphurbottom answered 3/12, 2012 at 13:47 Comment(0)
K
8

Have a look at the Callable class. This is usually submited via an executor service

It can return a future object which is returned when the thread completes

Keffer answered 3/12, 2012 at 13:42 Comment(0)
A
7

Yes, there are workaround. Just use queue and put into it value which you want to return. And take this value from another thread.

public class RunnableClass implements Runnable{

        private final BlockingQueue<jaxbResponse> queue;


        public RunnableClass(BlockingQueue<jaxbResponse> queue) {
            this.queue = queue;
        }

        public void run() {
            int id;
            id =inputProxy.input(chain);
            queue.put(outputProxy.input());
        }
    }


    public class Endpoint{
        public method_(){
            BlockingQueue<jaxbResponse> queue = new LinkedBlockingQueue<>();

            RunnableClass runcls = new RunnableClass(queue);
            runcls.run()

            jaxbResponse response = queue.take(); // waits until takes value from queue
        }
    }
Achromatous answered 4/11, 2017 at 6:35 Comment(1)
Very nice, got me out of a problem where the method would only accept Runnable. Thanks.Analog
R
3

If you add a field to RunnableClass you can set it in run and read it in method_. However, Runnable is a poor (the Java keyword) interface as it tells you nothing about the (the concept) interface (only useful line of the API docs: "The general contract of the method run is that it may take any action whatsoever."). Much better to use a more meaningful interface (that may return something).

Randolphrandom answered 3/12, 2012 at 13:46 Comment(2)
Can you provide example of meaningful interface?Olympian
Look at OnClickHandlerMiosis
C
3

One way is, we have to use Future - Callable approach.

Another way is, Instead of returning value, you can hold in object

Example:

class MainThread {
    public void startMyThread() {
        Object requiredObject = new Object(); //Map/List/OwnClass
        Thread myThread = new Thread(new RunnableObject(requiredObject)).start();
        myThread.join();

        System.out.println(requiredObject.getRequiredValue());    
    }
}



class RunnableObject implements Runnable {
    private Object requiredObject;

    public RunnableObject(Object requiredObject) {
        this.requiredObject = requiredObject;
    }

    public void run() {
        requiredObject.setRequiredValue(xxxxx);
    }
}

Because object scope is in the same scope so that you can pass object to thread and can retrieve in the main scope. But, most important thing is, we have to use join() method. Because main scope should be waiting for thread completion of its task.

For multiple thread case, you can use List/Map to hold the values from threads.

Concertante answered 8/10, 2014 at 14:38 Comment(2)
requiredObject.setRequiredValue() is not a method in Object. A more sophisticated approach would be needed to do what are trying to do: requiredObject = result; & Object getResult() { return requiredObject; }. Also starting a new Thread has nothing to do with the original question, nor is it necessary for the answer. BTW: Using Callable as answered by Narendra Pathai is definitely a better way.Coition
here, Object is Map/List/OwnClass which was already mentioned in comment. And also I clearly mention using the member names. ** required object / required value.** If it is custom class, we can write setter and getter methods.Concertante
E
1

Try the following

public abstract class ReturnRunnable<T> implements Runnable {

    public abstract T runForResult();

    @Override
    public void run() {
        runForResult();
    }
}
Extinction answered 5/9, 2018 at 17:42 Comment(0)
C
0

Take a look at the callable interface, perhaps this suites your needs. You can also try to get the value of the response field by calling a setter-method inside of your run() method

public void run() {
    int id;
    id =inputProxy.input(chain);
    response = outputProxy.input();
    OuterClass.setResponseData(response);

}
Condemn answered 3/12, 2012 at 13:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.