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