Java Concurrency – Future, Callable and Executor Example

Concurrent programming is now a lot easier in java with the introduction of new classes in java.util.concurrent package. The most important classes to focus are

  1. Executor
  2. Callable
  3. Future

Before looking into each of the above classes in detail, let us take a quick look at what concurrency is.

What is Concurrency

Concurrency is a technique that enables the execution of several tasks in parallel. These  can be parts of the same program or different programs itself. If  a big task can be split into small chunks and if each of those chunks can be executed in parallel, it can result in better response times and throughput. When different parts of a program are run in parallel, usually light weight processes called Threads are used. The moment you use threads, you need to have proper mechanisms to allow access to shared resources, proper management of thread life cycle, scheduling etc. The classes in java.util.concurrent package helps in dealing with many of these challenges.


Before the introduction of Executor framework in JDK 1.5, thread management was the responsibility of the developer and there was no framework for that in JDK. Developers handled the creation of the threads and its management along with the actual business logic. From a design and coding perspective, this is not an ideal situation, when you take into account the benefits gained by following “separation of concerns” design idea.

It makes sense to separate out the thread management and creation from the rest of the program and that is what executor framework does. An executor abstracts thread management activities like creation, scheduling etc. Instead of directly creating a thread, a Runnable class is submitted to an executor and executor handles its execution. ExecutorService – a more refined interface than Executor is used in practical scenarios as it provides support for Callable and Future. We will look at Callable and Future in the coming sections. Note: ExecutorService extends from Executor.

The  java.util.concurrent package provides three executor interfaces:

  1. Executor – a simple interface that supports launching new taks
  2. ExecutorService – a sub interface of Executor, which adds features that help manage the life cycle , both of the individual tasks and the executor itself.
  3. ScheduledExecutorService – a sub interface of ExecutorService, supports future and/or periodic execution of tasks.

ThreadPoolExecutor, ScheduledThreadPoolExecutor and ForkJoinPool are some of the important executor implementations available in JDK

High level Steps break down

At a high level, writing concurrent programs using the executor framework involves the following

  1. Define a class / task that implements either Runnable or Callable interface
  2. Configure and implementation of ExecutorService and submit the task
  3. Use the Future class to retrieve the result if the task is a Callable task

Let us look at the difference between a Runnable and Callable. A Runnable interface do not return a result whereas a Callable allows to return values after completion. When a Callable is submitted to the executor framework, it returns an object of type java.util.concurrent.Future. The future can be used to retrieve results

Runnable Example

Runnable Task




Callable Example

Callable Task



You may shutdown() method to stop the executor once all processing needs are over.

Share This:

Leave a Reply

Your email address will not be published. Required fields are marked *