Make delicious recipes!


A Thread Pool (TP) maintains a Blocking Queue of tasks and an array of Threads to run them. Threads from the array keep on dequeing the BQ (which blocks if its empty) and execute tasks if it has any.

The BQ blocks if its full (and can optionally reject too).

That’s why Thread-Pools take 2 arguments : Max no of threads to run and Max size of BQ


ExecutorService and ScheduledExecutorService are interfaces to thread-pools and the classes implementing them are ThreadPoolExecutor and ScheduledThreadPoolExecutor

ThreadPoolExecutor takes a Runnable or Callable and returns a Future.

The executor then executes the FutureTask at some point in the future whose result can be obtained by calling get() in the future object (Note: If Runnable was submitted, then null is returned). Future.get() call is blocking and returns only when that task is complete.

Advantage of ThreadPools is that they maintain a fixed number of threads in the pool which do not die after doing one task but switch on to the other tasks after finishing. Hence, the overhead of creating new Threads for each task is avoided and this improves performance.

To improve performance, one should have one ThreadPoolExecutor if possible. Having 2 thread-pool-executors in the system may not be good because if one of the pools’ blocking queue is empty, then its threads will just lie waiting while the other pool’s threads may be overworked at that very instant. If there were just one pool, then all the threads would be working together to give the maximum performance.


This executor optionally takes parameters to delay the execution of a task.

It also has parameters to:

  1. Run task repeatedly at every fixed interval

  2. Run task repeatedly with fixed delay between each run of the task.

If 2 tasks’ schedule matures at the same time, then they are run in FIFO fashion.


This is another implementation of ExecutorService whose worker threads have the

property of work-stealing i.e. if a worker thread is idle, it will attempt to share sub-task from a running thread.

Example usage:

ForkJoinPool forkJoinPool = new ForkJoinPool ();

HeavyWork masterTask = new HeavyWork (0, end); // where end is a big number.

forkJoinPool.invoke (masterTask);

The HeavyWork is defined below.

It see if the pool has any idle worker threads and distributes sub-tasks among them if any thread is available. If not, it proceeds with calculation of the task itself.

Difference between Callable and Runnable

Both interfaces are meant to be used for multi-threading purposes.

Runnable is the older interface while Callable was introduced in Java 5.

Callable returns a result and can throw a checked exception but Runnable cannot do both of these.

Runnable mandates implementation of void run ()

Callable mandates implementation of T call () throws Exception

Thread class cannot work with Callable objects.

Callable objects have to be submitted to an executor which returns a Future object on submission. Future has methods to retrieve the result of call() after execution.

Note: The fact that Callable can return a result is interesting as it’s not just a change in the method signature. When multiple threads are launched to complete a big task, the parent thread might not wait at the same place i.e. control of execution in parent thread might move ahead. In such a case, where would the call() method return its results and where would it throw an exception?

It turns out that the executor service maintains the result and exception thrown per thread.

When Future.get() is called, it checks if the corresponding thread has completed. If yes, then it returns the result (or the exception), else it blocks till called thread completes.

Like us on Facebook to remain in touch
with the latest in technology and tutorials!

Got a thought to share or found a
bug in the code?
We'd love to hear from you:

Email: (Your email is not shared with anybody)

Facebook comments:

Site Owner: Sachin Goyal