2405. Java Concurrency - Callable and Future
Callable, Future, and FutureTask


Volatile, Final and Atomics.

1. Callables and Futures

A Runnable encapsulates a task that runs asynchronously; you can think of it as an asynchronous method with no parameters and no return value. A Callable is similar to a Runnable, but it returns a value. The Callable interface is a parameterized type, with a single method call.

public interface Callable<V>
{
    V call() throws Exception; // V is the type of the returned value.
}

A Future holds the result of an asynchronous computation. The Future interface has the following methods:

public interface Future<V>
{
    V get() throws . . .;
    V get(long timeout, TimeUnit unit) throws . . .;
    void cancel(boolean mayInterrupt);
    boolean isCancelled();
    boolean isDone();
}

The FutureTask wrapper is a convenient mechanism for turning a Callable into both a Future and a Runnable—it implements both interfaces. For example:

Callable<Integer> myComputation = . . .;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task); // it's a Runnable
t.start();
...
Integer result = task.get(); // it's a Future

2. Example

The following two examples show how get to get result from from thread.

2.1 Runnable Only

Create a work thread with Runnable get generate random number.

public class RunnableWorker implements Runnable {
    // Shared object to store result
    private Object result = null;

    public void run() {
        Random random = new Random();
        Integer randomNumber = random.nextInt(5);

        // As run cannot throw any Exception
        try {
            Thread.sleep(randomNumber * 1000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Store the return value in result when done
        result = randomNumber;

        // Wake up threads blocked on the get() method
        synchronized(this) {
            notifyAll();
        }
    }

    public synchronized Object get() throws InterruptedException {
        while (result == null) {
            wait();
        }
        return result;
    }
}
  • Use notifyAll() method to notify other threads that the result is ready.
  • Use wait() method to let the caller keep waiting until the result is ready.

Create a main thread with 5 tasks. Call the get() method to receive the result for each task.

public class RunnableExample {
    public static void main(String[] args) throws Exception {
        RunnableWorker[] tasks = new RunnableWorker[5];

        System.out.println("Creating tasks...");
        for (int i = 0; i < 5; i++) {
            tasks[i] = new RunnableWorker();
            Thread t = new Thread(tasks[i]);
            t.start();
        }

        System.out.println("Waiting results...");
        for (int i = 0; i < 5; i++) {
            System.out.println(tasks[i].get());
        }
    }
}

Output.

Creating tasks...
Waiting results...
3
1
0
3
2

2.2 Callable + FurtureTask

Create a work thread with Callable get generate random number.

public class CallableWorker implements Callable {
    public Object call() throws Exception {
        Random random = new Random();
        Integer randomNumber = random.nextInt(5);

        Thread.sleep(randomNumber * 1000);

        return randomNumber;
    }
}

Create a main thread to use Future to get result from Callable.

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class CallableExample {
    public static void main(String[] args) throws Exception {
        // FutureTask is a concrete class that implements both Runnable and Future
        FutureTask[] tasks = new FutureTask[5];

        System.out.println("Creating tasks...");
        for (int i = 0; i < 5; i++) {
            Callable callable = new CallableWorker();

            // Create the FutureTask with Callable
            tasks[i] = new FutureTask(callable);

            // As it implements Runnable, create Thread with FutureTask
            Thread t = new Thread(tasks[i]);
            t.start();
        }

        System.out.println("Waiting results...");
        for (int i = 0; i < 5; i++) {
            // As it implements Future, we can call get()
            System.out.println(tasks[i].get());

            // This method blocks till the result is obtained
            // The get method can throw checked exceptions
            // like when it is interrupted. This is the reason
            // for adding the throws clause to main
        }
    }
}

Output:

Creating tasks...
Waiting results...
2
4
0
0
3

3. Source Files

4. References