Home » Android » java – Returning value from Thread

java – Returning value from Thread

Posted by: admin March 11, 2020 Leave a comment

Questions:

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();
}
How to&Answers:

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

Answer:

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.

Answer:

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

Answer:

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

Answer:

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).

Answer:

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)
        {

        }
    };

Answer:

Java 8 provides CompletableFuture . it will be the one stop solution for this.
http://www.baeldung.com/java-completablefuture

Answer:

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.