119

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();
}
litterbugkid
  • 3,534
  • 7
  • 36
  • 54
  • 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 Feb 05 '12 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. – litterbugkid Feb 05 '12 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 Feb 05 '12 at 16:04
  • @JBNizet I'm not too sure what you mean.. would you mind explaining it in a different way? – litterbugkid Feb 05 '12 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 Feb 05 '12 at 19:56
  • @JBNizet I'm not blocking immediately though. I'm trying to log gps trails using gps satellities. So I need to use Threads so it continually gets location data, and sleeps while a location hasn't been found. It does this in the background. – litterbugkid Feb 05 '12 at 22:10
  • @Neeta - It sounds like you need callbacks. Callbacks are for when you want to run some code based on an asynchronous event. – OrhanC1 May 29 '14 at 15:13
  • Possible duplicate of [How can a Thread return a value after finishing its job?](http://stackoverflow.com/questions/3141158/how-can-a-thread-return-a-value-after-finishing-its-job) – rogerdpack Oct 28 '15 at 17:42

9 Answers9

133

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.

Steve Moretz
  • 2,758
  • 1
  • 17
  • 31
Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
86

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();
}
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Adam Zalcman
  • 26,643
  • 4
  • 71
  • 92
  • 7
    Um... no. This code is not correct. Access to value is not correctly synchronized. – G. Blake Meike Jun 14 '14 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](http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.4)) 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). – Adam Zalcman Aug 22 '14 at 18:09
  • Looks like you are right about the Latch! ...in which case, the synchronization of the run method is useless. – G. Blake Meike Aug 22 '14 at 18:39
  • Good point. I must have copy-pasted from OP's code. Corrected. – Adam Zalcman Aug 22 '14 at 18:40
  • Here is an example of CountDownLatch: https://developer.android.com/reference/java/util/concurrent/CountDownLatch.html – Seagull Oct 27 '17 at 07:21
33

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();
}
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
Detheroc
  • 1,833
  • 15
  • 19
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

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
  • 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 – Gaurav Pangam Dec 10 '16 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 – portfoliobuilder Nov 29 '18 at 00:33
9

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
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Vinto
  • 356
  • 3
  • 7
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).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • "then it should wait for the thread to finish, which makes using threads a bit pointless" great point! – likejudo Mar 04 '13 at 19:46
  • 4
    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 Oct 23 '14 at 01: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)
        {

        }
    };
bitsabhi
  • 728
  • 8
  • 12
  • can you explain what's happening here? where does the Long result come from? since the call() is not returning anything. – Skadoosh Mar 21 '21 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.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

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);
}

Joel Chu
  • 828
  • 1
  • 9
  • 25