Java Concurrency: Difference between Executor and Executors

In Java concurrency, Executor and Executors play pivotal roles but serve different purposes. Understanding the distinction between these two is crucial for effectively managing concurrent tasks in Java applications.


This is an interface designed to abstract the execution of tasks in a thread. The Executor interface provides a single method, execute(Runnable command)which is intended to execute the given command at some time in the future.

void execute(Runnable command);

This method is used to submit a task for execution.

Why Use Executor?

  • Decoupling of task submission from execution: Allows you to submit tasks without worrying about the details of how they will be run, whether it’s on a single thread, a thread pool, or some other mechanism.
  • Simplified thread management: Reduces the complexity of handling threads directly, thus minimizing the risk of common concurrency issues.

Example: Using Executor

Imagine a simple scenario where you need to execute several tasks asynchronously:

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class SimpleExecutorExample {
    public static void main(String[] args) {
        Executor executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> System.out.println("Task 1 executed by " + Thread.currentThread().getName()));
        executor.execute(() -> System.out.println("Task 2 executed by " + Thread.currentThread().getName()));

In this example, Executors.newSingleThreadExecutor() creates an executor that runs tasks sequentially on a single background thread.


While Executor provides the foundation, the Executors class offers a suite of static methods to create pre-configured executor services. These services are more flexible and powerful, capable of handling complex concurrency scenarios with ease.

Executors Factory Methods

Some of the key factory methods in Executors include:

  • newFixedThreadPool(int nThreads): Creates a thread pool with a fixed number of threads. Useful for controlling the maximum number of concurrent threads.
  • newCachedThreadPool(): Creates a thread pool that creates new threads as needed but will reuse previously constructed threads when available.
  • newSingleThreadExecutor(): Creates an executor that executes tasks sequentially in a single thread.

Example: Using Executors to Create a Thread Pool

Let’s use Executors to manage a pool of threads for executing multiple tasks concurrently:

javaCopy code

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executorService.execute(() -> {
                System.out.println("Executing task " + taskId + " via " + Thread.currentThread().getName());
        executorService.shutdown(); // Initiates a graceful shutdown

In this scenario, Executors.newFixedThreadPool(5) creates a pool of 5 threads. Tasks are submitted to the pool and executed as threads become available. This demonstrates how Executors can be used to efficiently manage a group of threads for concurrent task execution.



About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.

You may also like

Blog Design Pattern

Understanding the Builder Design Pattern in Java | Creational Design Patterns | CodeTechSummit

Overview The Builder design pattern is a creational pattern used to construct a complex object step by step. It separates
Blog Tech Toolkit

Base64 Decode

Base64 encoding is a technique used to encode binary data into ASCII characters, making it easier to transmit data over