Skip to content
Dev Dump

Java Executors Utility Class

The Executors class provides factory methods to create different types of thread pools and executors, which are commonly used in backend development.

The Executors class offers several factory methods to create thread pools with different characteristics:

  • newSingleThreadExecutor(): Creates a single-threaded executor
  • newFixedThreadPool(int nThreads): Creates a thread pool with a fixed number of threads
  • newCachedThreadPool(): Creates a thread pool that creates new threads as needed
  • newScheduledThreadPool(int corePoolSize): Creates a thread pool for scheduling tasks
  • newWorkStealingPool(): Creates a thread pool that uses work-stealing for load balancing

A single-threaded executor ensures that tasks are executed sequentially in a single thread.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 5; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Executing Task " + taskId + " in thread: " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}

A fixed-thread pool creates a pool with a fixed number of threads. Tasks are queued if all threads are busy.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 10; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Executing Task " + taskId + " in thread: " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}

A cached-thread pool creates new threads as needed and reuses previously created threads when available. It is suitable for short-lived tasks.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Executing Task " + taskId + " in thread: " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}

A scheduled thread pool is used to schedule tasks to run after a delay or periodically.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExample {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// Schedule a task to run after a delay
scheduler.schedule(() -> {
System.out.println("Task executed after 3 seconds delay in thread: " + Thread.currentThread().getName());
}, 3, TimeUnit.SECONDS);
// Schedule a task to run periodically
scheduler.scheduleAtFixedRate(() -> {
System.out.println("Periodic task executed in thread: " + Thread.currentThread().getName());
}, 1, 2, TimeUnit.SECONDS);
// Schedule a task with a fixed delay between executions
scheduler.scheduleWithFixedDelay(() -> {
System.out.println("Task executed with fixed delay in thread: " + Thread.currentThread().getName());
}, 1, 2, TimeUnit.SECONDS);
}
}

A work-stealing pool is introduced in Java 8. It creates a pool of threads that dynamically balance the workload among themselves.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WorkStealingPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newWorkStealingPool();
for (int i = 1; i <= 10; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Executing Task " + taskId + " in thread: " + Thread.currentThread().getName());
});
}
// Since work-stealing pool uses daemon threads, we need to wait for tasks to complete
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

A single-threaded scheduled executor is used to schedule tasks in a single thread.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SingleThreadScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(() -> {
System.out.println("Task executed after 2 seconds delay in thread: " + Thread.currentThread().getName());
}, 2, TimeUnit.SECONDS);
scheduler.shutdown();
}
}

It is important to shut down the executor after tasks are completed to release resources.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ShutdownExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 1; i <= 5; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("Executing Task " + taskId + " in thread: " + Thread.currentThread().getName());
});
}
executor.shutdown(); // Initiates an orderly shutdown
System.out.println("Executor shutdown initiated.");
}
}
  1. Always shut down executors when they are no longer needed
  2. Choose the appropriate executor type based on your use case:
    • Use SingleThreadExecutor for sequential tasks
    • Use FixedThreadPool for CPU-intensive tasks
    • Use CachedThreadPool for short-lived tasks
    • Use ScheduledThreadPool for periodic tasks
    • Use WorkStealingPool for dynamic workload balancing
  3. Consider the number of threads carefully to avoid resource exhaustion
  4. Handle exceptions appropriately in submitted tasks

a87685de964311c66e0db47bb81d9ed5_MD5