从线程返回值
我有一个HandlerThread
方法。 Thread
值被改变了,我想把它返回给test()
方法。 有没有办法做到这一点?
public void test() { Thread uiThread = new HandlerThread("UIHandler"){ public synchronized void run(){ int value; value = 2; //To be returned to test() } }; uiThread.start(); }
您可以使用本地最终variables数组。 variables需要是非原始types的,所以你可以使用一个数组。 您还需要同步这两个线程,例如使用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. }
你也可以像这样使用Executor
和Callable
:
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(); }
通常你会这样做
public class Foo implements Runnable { private volatile int value; @Override public void run() { value = 2; } public int getValue() { return value; } }
然后你可以创build线程并检索值(假设已经设置了该值)
Foo foo = new Foo(); new Thread(foo).start(); // ... join through some method int value = foo.getValue();
tl;dr
一个线程不能返回一个值(至less不是没有callback机制)。 你应该像一个普通的类一样引用一个线程,并要求价值。
您正在寻找的可能是Callable<V>
接口来代替Runnable
,并使用Future<V>
对象检索值,这也可以让您等待,直到计算出值。 你可以通过一个ExecutorService
实现这一点,你可以从Executors.newSingleThreadExecutor()
获得这个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(); }
这个解决scheme如何?
它不使用Thread类,但是它是并发的,并且在某种程度上它完全符合你的要求
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;} });
现在你只需要说value.get()
当你需要获取返回的值的时候,线程就会在第二个value
一个值,所以你永远不必对它说threadName.start()
。
Future
是什么,是该计划的承诺 ,你承诺该计划,你会在不久的将来获得它需要的价值
如果在完成之前调用.get()
,那么调用它的线程将只是等待完成
如果你想从调用方法的值,那么它应该等待线程完成,这使得使用线程有点没有意义。
要直接回答你的问题,该值可以存储在任何可调对象中,调用方法和线程都有一个引用。 你可以使用外部的this
,但这不会是特别有用的,除了一些简单的例子。
关于代码的一点注意:扩展Thread
通常是不好的风格。 事实上,不必要地扩展课程是一个坏主意。 我注意到你run
方法是由于某种原因同步的。 现在,因为在这种情况下的对象是Thread
你可能会干扰任何Thread
使用它的锁(在参考实现, join
,IIRC)。
在上面的回答中描述的使用Future可以完成这个工作,但是与f.get()相比稍微不显着,会阻塞线程,直到获得违反并发的结果。
最好的解决scheme是使用Guava的ListenableFuture。 一个例子 :
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) { } };
通过对代码进行小的修改,可以以更通用的方式实现它。
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();
解答:
- 在UI线程中创build一个名为
responseHandler
- 从UI线程的
Looper
初始化这个Handler
。 - 在
HandlerThread
,在这个responseHandler
上发布消息 -
handleMessgae
显示从消息收到的值Toast
。 此消息对象是通用的,您可以发送不同types的属性。
使用这种方法,您可以在不同的时间点将多个值发送到UI线程。 你可以在这个HandlerThread
上运行(post)许多Runnable
对象,每个Runnable
可以在Message
对象中设置值,这个值可以被UI Thread接收。