129

I have a method with a HandlerThread. A value gets changed inside the Thread and I'd like to return it to the test() method. Is there a way to do this?

public void test()
{   
    Thread uiThread = new HandlerThread("UIHandler"){
        public synchronized void run(){
            int value; 
            value = 2; //To be returned to test()
        }
    };
    uiThread.start();
}
8
  • If the main thread must wait for the handler thread to finish before returning from the method, why use a handler thread in the first place?
    – JB Nizet
    Commented Feb 5, 2012 at 11:43
  • 2
    @JBNizet I didnt include the complexity of what the Thread actually does. It's getting gps coordinates so yes I do need a Thread. Commented Feb 5, 2012 at 11:59
  • 2
    Regardless of the complexity of the thread, if the thread that laustarts it immediately waits for its result after starting it, there is no point in starting a different thread: the starting thread will be blocked as if it did the work itself.
    – JB Nizet
    Commented Feb 5, 2012 at 16:04
  • @JBNizet I'm not too sure what you mean.. would you mind explaining it in a different way? Commented Feb 5, 2012 at 19:41
  • 1
    A thread is used to be able to execute something in the background, and be able to do something else while the background thread executes. If you start a thread, and then block immediately until the thread stops, you could do the task done by the thread yourself, and it wouldn't make any difference, except it would be much simpler.
    – JB Nizet
    Commented Feb 5, 2012 at 19:56

9 Answers 9

146

Usually you would do it something like this

 public class Foo implements Runnable {
     private volatile int value;

     @Override
     public void run() {
        value = 2;
     }

     public int getValue() {
         return value;
     }
 }

Then you can create the thread and retrieve the value (given that the value has been set)

Foo foo = new Foo();
Thread thread = new Thread(foo);
thread.start();
thread.join();
int value = foo.getValue();

tl;dr a thread cannot return a value (at least not without a callback mechanism). You should reference a thread like an ordinary class and ask for the value.

8
  • 2
    Does this really work? I get The method getValue() is undefined for the type Thread.
    – pmichna
    Commented Nov 26, 2013 at 15:07
  • 2
    @pmichna, good spotting. Changing from t.getValue() to foo.getValue(). Commented Nov 26, 2013 at 15:46
  • 4
    Yes! Well done! "volatile" ftw! Unlike the accepted answer, this one is correct! Commented Jun 14, 2014 at 14:40
  • 12
    @HamzahMalik To make sure the thread finishes use Thread t = new Thread(foo); t.start(); t.join(); foo.getValue();. The t.join() blocks until the thread is finished.
    – Daniel
    Commented Dec 16, 2014 at 17:03
  • 2
    @HariKiran yes correct , each thread returns an independent value. Commented Dec 30, 2019 at 2:02
91

You can use a local final variable array. The variable needs to be of non-primitive type, so you can use an array. You also need to synchronize the two threads, for example using a CountDownLatch:

public void test()
{   
    final CountDownLatch latch = new CountDownLatch(1);
    final int[] value = new int[1];
    Thread uiThread = new HandlerThread("UIHandler"){
        @Override
        public void run(){
            value[0] = 2;
            latch.countDown(); // Release await() in the test thread.
        }
    };
    uiThread.start();
    latch.await(); // Wait for countDown() in the UI thread. Or could uiThread.join();
    // value[0] holds 2 at this point.
}

You can also use an Executor and a Callable like this:

public void test() throws InterruptedException, ExecutionException
{   
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Callable<Integer> callable = new Callable<Integer>() {
        @Override
        public Integer call() {
            return 2;
        }
    };
    Future<Integer> future = executor.submit(callable);
    // future.get() returns 2 or raises an exception if the thread dies, so safer
    executor.shutdown();
}
5
  • 7
    Um... no. This code is not correct. Access to value is not correctly synchronized. Commented Jun 14, 2014 at 14:39
  • 6
    We don't actually need explicit synchronization for the accesses to value due to memory consistency guarantees of CountDownLatch. The value array creation happens-before uiThread start (program order rule) which synchronizes-with the assignment of 2 to value[0] (thread start) which happens-before latch.countDown() (program order rule) which happens-before latch.await() (guarantee from CountDownLatch) which happens-before the read from value[0] (program order rule). Commented Aug 22, 2014 at 18:09
  • Looks like you are right about the Latch! ...in which case, the synchronization of the run method is useless. Commented Aug 22, 2014 at 18:39
  • Good point. I must have copy-pasted from OP's code. Corrected. Commented Aug 22, 2014 at 18:40
  • Here is an example of CountDownLatch: developer.android.com/reference/java/util/concurrent/…
    – Seagull
    Commented Oct 27, 2017 at 7:21
37

What you are looking for is probably the Callable<V> interface in place of Runnable, and retrieving the value with a Future<V> object, which also lets you wait until the value has been computed. You can achieve this with an ExecutorService, which you can get from Executors.newSingleThreadExecutor() .

public void test() {
    int x;
    ExecutorService es = Executors.newSingleThreadExecutor();
    Future<Integer> result = es.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            // the other thread
            return 2;
        }
    });
    try {
        x = result.get();
    } catch (Exception e) {
        // failed
    }
    es.shutdown();
}
11

How about this solution?

It doesn't use the Thread class, but it IS concurrent, and in a way it does exactly what you request

ExecutorService pool = Executors.newFixedThreadPool(2); // creates a pool of threads for the Future to draw from

Future<Integer> value = pool.submit(new Callable<Integer>() {
    @Override
    public Integer call() {return 2;}
});

Now all you do is say value.get() whenever you need to grab your returned value, the thread is started the very second you give value a value so you don't ever have to say threadName.start() on it.

What a Future is, is a promise to the program, you promise the program that you'll get it the value it needs sometime in the near future

If you call .get() on it before it's done, the thread that's calling it will simply just wait until it's done

2
  • I seperated the provided code into two things one is the pool initiation which i do in the Application class(I am talking about android) and secondly i use the pool in the places where i need it...Also regarding using Executors.newFixedThreadPool(2) i used Executors.newSingleThreadExecutor()..as i needed only one task running at a time for server calls...Your Answer is perfect @electirc coffee thanks Commented Dec 10, 2016 at 10:07
  • @Electric how do you know when to get the value? I believe the original poster wanted to return this value in his method. Using the .get() call will retrieve the value, but only if the operation is completed. He wouldn't know with a blind .get() call Commented Nov 29, 2018 at 0:33
11

From Java 8 onwards we have CompletableFuture. On your case, you may use the method supplyAsync to get the result after execution.

Please find some reference here.

    CompletableFuture<Integer> completableFuture
     ��= CompletableFuture.supplyAsync(() -> yourMethod());

   completableFuture.get() //gives you the value
5

If you want the value from the calling method, then it should wait for the thread to finish, which makes using threads a bit pointless.

To directly answer you question, the value can be stored in any mutable object both the calling method and the thread both have a reference to. You could use the outer this, but that isn't going to be particularly useful other than for trivial examples.

A little note on the code in the question: Extending Thread is usually poor style. Indeed extending classes unnecessarily is a bad idea. I notice you run method is synchronised for some reason. Now as the object in this case is the Thread you may interfere with whatever Thread uses its lock for (in the reference implementation, something to do with join, IIRC).

2
  • "then it should wait for the thread to finish, which makes using threads a bit pointless" great point!
    – likejudo
    Commented Mar 4, 2013 at 19:46
  • 5
    It's usually pointless, but in Android you can't make a network request to a server on the main Thread (to keep the app responsive) so you'll have to use a network thread. There are scenarios in which you need the result before the app can resume.
    – SuperFrog
    Commented Oct 23, 2014 at 1:34
1

Using Future described in above answers does the job, but a bit less significantly as f.get(), blocks the thread until it gets the result, which violates concurrency.

Best solution is to use Guava's ListenableFuture. An example :

    ListenableFuture<Void> future = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1, new NamedThreadFactory).submit(new Callable<Void>()
    {
        @Override
        public Void call() throws Exception
        {
            someBackgroundTask();
        }
    });
    Futures.addCallback(future, new FutureCallback<Long>()
    {
        @Override
        public void onSuccess(Long result)
        {
            doSomething();
        }

        @Override
        public void onFailure(Throwable t)
        {

        }
    };
1
  • can you explain what's happening here? where does the Long result come from? since the call() is not returning anything.
    – Skadoosh
    Commented Mar 21, 2021 at 17:48
1

With small modifications to your code, you can achieve it in a more generic way.

 final Handler responseHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                //txtView.setText((String) msg.obj);
                Toast.makeText(MainActivity.this,
                        "Result from UIHandlerThread:"+(int)msg.obj,
                        Toast.LENGTH_LONG)
                        .show();
            }
        };

        HandlerThread handlerThread = new HandlerThread("UIHandlerThread"){
            public void run(){
                Integer a = 2;
                Message msg = new Message();
                msg.obj = a;
                responseHandler.sendMessage(msg);
                System.out.println(a);
            }
        };
        handlerThread.start();

Solution :

  1. Create a Handler in UI Thread,which is called as responseHandler
  2. Initialize this Handler from Looper of UI Thread.
  3. In HandlerThread, post message on this responseHandler
  4. handleMessgae shows a Toast with value received from message. This Message object is generic and you can send different type of attributes.

With this approach, you can send multiple values to UI thread at different point of times. You can run (post) many Runnable objects on this HandlerThread and each Runnable can set value in Message object, which can be received by UI Thread.

1

Here is a cleaner approach, you just need a bit change to your existing code. The goal is to get the result from the the Thread. It doesn't really have to be return a result. Instead, using a callback style to take that result and do further processing.

public class Test {

  public static void main(String[] args) {
    String str = args[0];
    int count = 0;

    Thread t = new Thread(() ->
      someFuncToRun(str, count, (value) -> {
        System.out.println(value);
        return value;
      }));

    t.start();
  }
  // Here I even run a recursive method because run things in the 
  // a thread sometime is to delegate those heavy lifting elsewhere
  public static String someFuncToRun(String str, int ctn, Callback<String> p) {
    ++ctn;
    if (ctn == 10) {
      System.out.println("End here");
      return p.cb(str);
    }
    System.out.println(ctn + " times");
    return someFuncToRun(str + " +1", ctn, p);
  }
}

// The key is here, this allow you to pass a lambda callback to your method 
// update: use generic to allow passing different type of data
// you could event make it <T,S> so input one type return another type  
interface Callback<T> {
    public T cb(T a);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.