我有一个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();
}
答案 0 :(得分:65)
通常你会这样做
public class Foo implements Runnable {
private volatile int value;
@Override
public void run() {
value = 2;
}
public int getValue() {
return value;
}
}
然后你可以创建线程并检索值(假设已经设置了值)
Foo foo = new Foo();
Thread thread = new Thread(foo);
thread.start();
thread.join();
int value = foo.getValue();
tl;dr
线程无法返回值(至少没有回调机制)。您应该像普通类一样引用一个线程并询问该值。
答案 1 :(得分:65)
您可以使用本地最终变量数组。变量必须是非基本类型,因此您可以使用数组。您还需要同步两个线程,例如使用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.
}
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();
}
答案 2 :(得分:26)
您正在寻找的可能是Callable<V>
接口代替Runnable
,并使用Future<V>
对象检索值,这也让您等到计算出值。您可以使用ExecutorService
来实现此目的,您可以从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();
}
答案 3 :(得分:6)
这个解决方案怎么样?
它不使用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()
1}}就可以了。
该程序的Future
是承诺,您承诺程序在不久的将来有时会获得它所需的价值
如果你在它完成之前打电话给.get()
,那么正在调用它的线程就会等到它完成之后
答案 4 :(得分:4)
如果你想要调用方法的值,那么它应该等待线程完成,这使得使用线程有点无意义。
要直接回答你的问题,可以将值存储在任何可变对象中,调用方法和线程都有引用。你可以使用外部this
,但除了琐碎的例子之外,这不会特别有用。
关于问题代码的一点注意事项:扩展Thread
通常是糟糕的风格。实际上,不必要地扩展类是一个坏主意。我注意到你run
方法由于某种原因被同步。现在,作为此案例中的对象是Thread
,您可能会干扰Thread
使用其锁定的任何内容(在参考实现中,与join
,IIRC有关。)
答案 5 :(得分:1)
使用上述答案中描述的Future完成了这项工作,但是f.get()稍微不那么明显,阻塞了线程,直到它获得结果,这违反了并发性。
最佳解决方案是使用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)
{
}
};
答案 6 :(得分:1)
Java 8提供CompletableFuture。这将是一站式解决方案。 http://www.baeldung.com/java-completablefuture
答案 7 :(得分:0)
通过对代码的少量修改,您可以以更通用的方式实现它。
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();
解决方案:
Handler
,称为responseHandler
Handler
初始化此Looper
。 HandlerThread
中,在此responseHandler
handleMessgae
显示Toast
,其中包含从邮件中收到的值。此Message对象是通用的,您可以发送不同类型的属性。使用此方法,您可以在不同的时间点向UI线程发送多个值。您可以在此Runnable
上运行(发布)许多HandlerThread
个对象,并且每个Runnable
都可以在Message
对象中设置值,这可以由UI线程接收。
答案 8 :(得分:0)
这是一种更简洁的方法,您只需要对现有代码进行一些更改。目标是从线程中获取结果。它不一定是 return
结果。相反,使用回调样式来获取该结果并进行进一步处理。
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);
}
答案 9 :(得分:0)
您可以使用 java.util.concurrent.atomic
中的类,例如 AtomicInteger。
public static void main(String[] args) throws InterruptedException {
AtomicInteger value = new AtomicInteger(0);
Thread thread = new Thread(() -> value.set(2));
thread.start();
thread.join();
System.out.println(value.get());
}