CS680 Using a Thread for Long-running Work
There are several ways to do this. You can set up a thread and start it
easily enough. The challenge comes in knowing when its result is ready
for use.
One way is to use futures. A future is an object that represents a
result that may not be ready yet. You can query the future to see if
the data is ready or not, and/or call its method that waits for the
data to be ready and returns it. In Java, the public interface
Future<V> looks like this:
public interface
Future<V>
{
V get() throws ... <--blocks until data ready
V get(timeout args) throws ...
void cancel(...);
boolean isCancelled();
boolean isDone();
}
Here is an example big computation. To make it fit with FutureTask and
Futures, we put the computation in method "call" specified by the
Callable interface.
// A sample big computation to run in a separate thread
import java.util.concurrent.Callable;
public class BigSumWork implements Callable<Integer> {
private int stride;
private int sum; // so we can see intermediate results
BigSumWork(int s) {
stride = s;
}
public Integer call() {
sum = 0;
// This overflows, but just goes on...
for (int i = 0; i < 1000000; i += stride) {
sum += i;
}
return new Integer(sum);
}
public int getBigSum() {
return sum;
}
}
FutureTaskTest (over for code)
We construct a new FutureTask from a Callable computation like that above.
The new FutureTask is both a Runnable for a thread and a Future that
can be handed off to something interested in the result of the
computation.
We feed the FutureTask to a new thread to get the computation done, and then check on its progress from our original thread.
// Sample showing use of separate thread for a big task
// using the convenient FutureTask wrapper
import java.util.concurrent.FutureTask;
public class FutureTaskTest {
public static void main(String[] args) {
try {
// our big computation--
BigSumWork workToDo = new BigSumWork(2);
// turn it into a FutureTask that returns an Integer
// A FutureTask is both a Future and a Runnable task
FutureTask<Integer>
futureTask = new
FutureTask<Integer>(workToDo);
// run the task in a thread (futureTask as Runnable)
Thread t = new Thread(futureTask);
t.start();
// Now it's running, can check on its progress
// Note that getBigSum is not synchronized data access
// It's just to show that something is happening
// The final result is properly synchronized
int result1 = workToDo.getBigSum();
boolean status1 = futureTask.isDone();
System.out.println("first value: " + result1
+ " future's status: " + status1);
int result2 = workToDo.getBigSum();
boolean status2 = futureTask.isDone();
System.out.println("second value: " + result2
+ " future's status: " + status2);
// OK, now wait for the final answer with future.get()
// i.e. using futureTask as Future
int result = futureTask.get(); // blocks until computed
System.out.println("result from get: " + result);
int result3 = workToDo.getBigSum();
System.out.println("third (final) value: " + result3);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output from run
first value: 0 future's status: false
second value: 74295780 future's status: false
result from get: 891396832
third (final) value: 891396832
Output from rerun
first value: 0 future's status: false
second value: 162396792 future's status: false
result from get: 891396832
third (final) value: 891396832