views:

117

answers:

2

How can return a variable from a thead (I have the threads handle too). Static variables will not work in this case.

Update: Here is one twist, how can I do this without having to block and wait for the result? I need to be able to poll the created thread and kill it if it is hanging for too long (eg> 1 minute), then continue on in the main thread if the spawned thread is taking too long.

+7  A: 

Use Callable<V> instead of Thread (or Runnable) so that you can get result as Future<V> and use ExecutorService to invoke it.

Here's an SSCCE, just copy'n'paste'n'run it:

package com.stackoverflow.q2413389;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {

    public static void main(String... args) throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();
        List<Future<String>> results = executor.invokeAll(Arrays.asList(new Task()));
        for (Future<String> result : results) {
            System.out.println(result.get()); // Prints "myResult" after 2 seconds.
        }
        executor.shutdown();
    }

}

class Task implements Callable<String> {

    public String call() throws Exception {
        Thread.sleep(2000); // Do your running task here, this example lasts 2 seconds.
        return "myResult";
    }

}

Update: as per your update with the question how to kill it after a timeout, make use of ScheduledExecutorService instead. Here's the slightly changed code:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
List<Future<String>> results = executor.invokeAll(Arrays.asList(new Task()), 1, TimeUnit.SECONDS); // Timeout of 1 second.
for (Future<String> result : results) {
    if (!result.isCancelled()) {
        System.out.println(result.get()); // Won't be printed as the "actual" processing took 2 seconds.
    } else {
        System.out.println("Task timed out.");
    }
}
executor.shutdown();
BalusC
This doesn't block right? I can still poll? reading the API it seems that calling the get on the future blocks.
Zombies
Do it at lower level. You'll need to have a thread which collects the results at any way.
BalusC
Could you add some explaination, please? Just general comments about the problem this code solve. I don't have possibility to run this code at the moment but it's really interesting.
Roman
Just "fire-and-forget" a simple `Thread` which in turn executes the tasks and collects the results. You could keep a handle of it to do the polling.
BalusC
What does `result.get()` do? Is it a new thread?
Roman
result.get() contains the return of the Callable thread.
lemon
@Roman: It returns *the* result, i.e. the return value of the `call()` method, which is in this example "myResult". The result type is controllable by the parameterized type, which is in this example just "plain" `<String>`.
BalusC
Thanks, it seems I understand what this code do. Of course, now I need to read something about use cases for this technique.
Roman
@Roman: I use under each `ScheduledExecutorService#scheduleAtFixedRate()` to run scheduled background jobs in webapps (initiated by `ServletContextListener#contextInitialized()`).
BalusC
+1  A: 

If I understand your question (how to access a thread object's member value) you can use this simple approach:

MyObject a = new MyObject(); new Thread(a).start();

Just remember to implement the Runnable interface for MyObject and to have appropriate Getters.

If you are wanting to return a variable you can create a member in the class And do a while-loop till the thread finishes execution.

Vals