Return value from Thread

I have a method with HandlerThread . The value changes inside Thread , and I would like to return it to the test() method. Is there any 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(); } 
+72
java android multithreading
Feb 05 2018-12-12T00:
source share
8 answers

You can use a local finite variable array. The variable must not be of a primitive type, so you can use an array. You also need to synchronize two threads, for example, using 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 Executor and Callable as follows:

 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(); } 
+62
Feb 05 2018-12-12T00:
source share

Usually you 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 a stream and get the value (assuming the value has been set)

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



tl;dr stream cannot return a value (at least without a callback mechanism). You must reference the stream as a regular class and request a value.

+61
Feb 05 '12 at 11:45
source share

What you are looking for is probably the Callable<V> interface instead of Runnable and retrieves the value using the Future<V> object, which also allows you to wait until the value is calculated. You can achieve this with the 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(); } 
+25
Feb 05 2018-12-12T00:
source share

How about this solution?

It does not use the Thread class, but it is parallel, and thus 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 capture the return value, the thread starts just a second when you give the value value, so you never need to say threadName.start() .

What is Future , this is a promise to the program, you promise the program that you will receive its value, which they will need in the near future

If you call .get() on it before it finishes, the thread calling it will just wait until it is executed

+6
Dec 28 '13 at 9:11
source share

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

To directly answer the question, the value can be stored in any mutable object, both the calling method and the stream to which there is a link. You can use the external this , but it will not be particularly useful, except for trivial examples.

A small note to the code in the question: Thread extension is usually bad. Indeed, expanding classes unnecessarily is a bad idea. I noticed that the run method is synchronized for some reason. Now, since the object in this case is Thread , you can interfere with what Thread uses its lock for (in the reference implementation, do something with join , IIRC).

+4
Feb 05 2018-12-12T00:
source share

Using Future, described in the answers above, does the job, but is slightly less important, since f.get () blocks the thread until it gets a result that violates concurrency.

The best solution is to use Guava ListenableFuture. 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
Aug 08 '15 at 18:13
source share

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

+1
Feb 23 '18 at 10:13
source share

With minor changes to your code, you can achieve this in a more general 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(); 

Decision:

  • Create a Handler in a UI thread called responseHandler
  • Initialize this Handler from the Looper UI thread.
  • In HandlerThread , post a message on this responseHandler
  • handleMessgae shows a Toast with the value received from the message. This Message object is generic and you can send attributes of different types.

With this approach, you can send multiple values ​​to the user interface stream at different points in time. You can run (publish) many Runnable objects on this HandlerThread , and each Runnable can set a value in the Message object, which can be received in the user interface thread.

0
Aug 29 '17 at 10:26
source share



All Articles