Как Thread может вернуть значение после завершения работы?
Скажем, у нас есть такой простой пример:
public Example extends Thread{
String temp;
public Example(){
}
@Override
public void run(){
.
.
.
.
temp = "a_value";
}
public static void main(String[] args) {
Example th = new Example();
th.start();
}
}
Как Thread после завершения работы вернет мне String temp?
Ответы
Ответ 1
Использовать (относительно) новый Callable<T>
вместо Runnable (доступно в версиях 1.5 и более поздних версий):
Вот пример (простой):
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(final String[] argv) {
final ExecutorService service;
final Future<String> task;
service = Executors.newFixedThreadPool(1);
task = service.submit(new Foo());
try {
final String str;
// waits the 10 seconds for the Callable.call to finish.
str = task.get(); // this raises ExecutionException if thread dies
System.out.println(str);
} catch(final InterruptedException ex) {
ex.printStackTrace();
} catch(final ExecutionException ex) {
ex.printStackTrace();
}
service.shutdownNow();
}
}
class Foo implements Callable<String> {
public String call() {
try {
// sleep for 10 seconds
Thread.sleep(10 * 1000);
} catch(final InterruptedException ex) {
ex.printStackTrace();
}
return ("Hello, World!");
}
}
Ответ 2
Посмотрите Future интерфейс javadoc. В нем есть пример использования, показывающий, как это сделать.
Ответ 3
Вы можете добиться этого с помощью шаблона Observer.
при завершении потока уведомляет всех слушателей о завершении работы, и они могут получить значение (через getter). Или он даже может отправить вычисленное значение.
Или вы можете использовать задачу, см. FutureTask, runnable (действительно, как указано ниже Callable), которая возвращает результат и может генерировать исключения.
Ответ 4
Если вы не хотите менять решение для использования объектов Callable, вы можете также использовать очереди и возвращать результат из потоков таким образом.
Я переписал ваш пример следующим образом:
import java.util.PriorityQueue;
import java.util.Queue;
public class GetResultFromThread {
public static void main(String[] args) throws Exception {
Queue<String> queue = new PriorityQueue<String>();
int expectedResults = 2;
for (int i = 0; i < expectedResults; i++) {
new Example(queue).start();
}
int receivedResults = 0;
while (receivedResults < expectedResults) {
if (!queue.isEmpty()) {
System.out.println(queue.poll());
receivedResults++;
}
Thread.sleep(1000);
}
}
}
class Example extends Thread {
private final Queue<String> results;
public Example(Queue<String> results) {
this.results = results;
}
@Override
public void run() {
results.add("result from thread");
}
}
Обратите внимание, что вы должны думать о синхронизации и concurrency!