Как 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!