The Executor, Callable, and Future are used for three different purposes.
The
Callable is the closest thing to Runnable, the biggest difference is that Callable's call() method has a return value while Runnable's run() method returns void. So think of Callable as a task which produces a result, and a Runnable as a task which does not.
The
Executor is a container used to run tasks. There are different varieties, and you can build your own, but the idea is you give an Executor a Runnable and it decides when, where, and how to call the run() method. The most common scenario for an Executor is a
Thread Pool, which contains and holds a bunch of running Threads and distributes tasks to the Threads to run.
There is a sub-interface of Executor called an ExecutorService, which acts like an Executor but also allows you to submit Callables as well as Runnables. When you submit a task to an ExecutorService you get a
Future, which is used to track the progress of the task that was run. It will let you cancel the task, check to see if its is done, or get the results (if the task was a Callable), waiting for it to complete if not done yet.