Understanding Java Callable, Future, and FutureTask for Retrieving Thread Results
This article explains how to create threads using Runnable or Thread, introduces the Callable and Future interfaces introduced in Java SE 5.0, compares them, shows how to use ExecutorService methods, and demonstrates retrieving results with FutureTask and example code.
In Java there are two ways to create a thread: implementing the Runnable interface or extending Thread , but both lack a way to obtain a return value after execution.
To get a result you can use the Callable and Future interfaces introduced in Java SE 5.0. Callable defines a call() method that can return a value and throw exceptions.
Runnable vs Callable Comparison
Runnable:
public interface Runnable {
public abstract void run();
}
Callable:
public interface Callable
{
V call() throws Exception;
}Callable Introduction
A Callable task can be submitted to a ThreadPoolExecutor or ScheduledThreadPoolExecutor because both implement ExecutorService . The ExecutorService provides several submit methods:
<T> Future<T> submit(Callable<T> task); // returns a Future with the result
<T> Future<T> submit(Runnable task, T result); // returns a Future that yields the given result
Future
submit(Runnable task); // returns a Future for a Runnable taskOther Methods
You can also wrap a Runnable into a Callable using the factory methods of Executors :
public static Callable
callable(Runnable task)
public static
Callable
callable(Runnable task, T result)Future<V> Interface
The Future<V> interface allows you to cancel a task, check if it is done, and retrieve the result with get() (optionally with a timeout):
public interface Future
{
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}Summary
Future provides three main capabilities: interrupting a running task, checking completion status, and obtaining the result after execution. Since Future is only an interface, you typically use its implementation FutureTask .
FutureTask
public class FutureTask
implements RunnableFuture
{ }
public interface RunnableFuture
extends Runnable, Future
{ void run(); }FutureTask implements both Runnable and Future , so it can be submitted directly to an Executor or run manually. It has two constructors:
public FutureTask(Callable
callable) { }
public FutureTask(Runnable runnable, V result) { }The task goes through three states: not started, running, and completed (or cancelled). The behavior of get() and cancel() depends on the current state.
Callable + FutureTask Example
public class ThreadDemo {
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
Callable
calTask = new Callable
() {
public String call() throws Exception {
return "返回值";
}
};
FutureTask
futureTask = new FutureTask(calTask);
es.submit(futureTask);
es.shutdown();
try {
Thread.sleep(2000);
System.out.println("主线程在执行其他任务");
if (futureTask.get() != null) {
System.out.println("futureTask.get()-->" + futureTask.get());
} else {
System.out.println("futureTask.get()未获取到结果");
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("主线程在执行完成");
}
}Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.