Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a parameter to a thread and get a return value?

public class CalculationThread implements Runnable {

    int input;
    int output;

    public CalculationThread(int input)
    {
        this.input = input;
    }

    public void run() {
        output = input + 1;
    }

    public int getResult() {
        return output;
    }
}

Somewhere else:

Thread thread = new Thread(new CalculationThread(1));
thread.start();
int result = thread.getResult();

Of course, thread.getResult() doesn't work (it tries to invoke this method from the Thread class).

You get what I want. How can I achieve this in Java?

like image 328
pmichna Avatar asked Nov 26 '13 15:11

pmichna


2 Answers

This a job for thread pools. You need to create a Callable<R> which is Runnable returning a value and send it to a thread pool.

The result of this operation is a Future<R> which is a pointer to this job which will contain a value of the computation, or will not if the job fails.

public static class CalculationJob implements Callable<Integer> {
    int input;

    public CalculationJob(int input) {
        this.input = input;
    }

    @Override
    public Integer call() throws Exception {
        return input + 1;
    }
}

public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(4);

    Future<Integer> result = executorService.submit(new CalculationJob(3));

    try {
        Integer integer = result.get(10, TimeUnit.MILLISECONDS);
        System.out.println("result: " + integer);
    } catch (Exception e) {
        // interrupts if there is any possible error
        result.cancel(true);
    }

    executorService.shutdown();
    executorService.awaitTermination(1, TimeUnit.SECONDS);
}

Prints:

result: 4
like image 90
Andrey Chaschev Avatar answered Oct 13 '22 20:10

Andrey Chaschev


The accepted answer is great. But it is not the simplest approach. There's no real need to use an ExecutorService if you just want to wait for the result of a thread. You can simply use java.util.concurrent.FutureTask, which is basically a Runnable wrapping a Callable which also implements the Future interface.

So step 1 is still make the calculation a Callable :

public class Calculation implements Callable<Integer> {

    private final int input;

    public Calculation(int input) {
        this.input = input;
    }

    @Override
    public Integer call() throws Exception {
        return input + 1;
    }
}

So where you need the asynchronous calculation you can do :

    FutureTask<Integer> task = new FutureTask<>(new Calculation(1561));
    new Thread(task).start();

    // ... do other stuff

    // when I really need the result :

    try {
        int result = task.get(); // this will wait for the task to finish, if it hasn't yet.
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } catch (ExecutionException e) {
        e.getCause().printStackTrace(); // e.getCause() holds the exception that happened on the calculation thread
    }

What the ExecutorService adds is managing a pool of threads to run the task on, but under the hood of an ExecutorService, basically the same thing happens.

like image 41
bowmore Avatar answered Oct 13 '22 19:10

bowmore