Java Executors newSingleThreadExecutor() Method

The Executors class in Java provides the newSingleThreadExecutor() method to create an executor that uses a single worker thread operating off an unbounded queue. 

This guide will cover the usage of the newSingleThreadExecutor() method, explain how it works, and provide concise examples to demonstrate its functionality in real-world use cases.

Introduction

The Executors.newSingleThreadExecutor() method creates an executor that ensures tasks are executed sequentially in the order they are submitted, using a single worker thread. This is useful when you need to enforce a strict order of execution for tasks.

newSingleThreadExecutor Method Syntax

The syntax for the newSingleThreadExecutor method is as follows:

public static ExecutorService newSingleThreadExecutor()
  • The method does not take any parameters.
  • The method returns an ExecutorService that can be used to manage asynchronous task execution with a single thread.

Examples

Example 1: Basic Usage

In this example, we create a single-thread executor and submit multiple tasks to it. The tasks will be executed sequentially by the same thread.

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

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        // Create a single-thread executor
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // Submit tasks to the executor
        for (int i = 0; i < 5; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shutdown the executor
        executor.shutdown();
    }
}

Output:

Executing task 1 by pool-1-thread-1
Task 1 completed by pool-1-thread-1
Executing task 2 by pool-1-thread-1
Task 2 completed by pool-1-thread-1
Executing task 3 by pool-1-thread-1
Task 3 completed by pool-1-thread-1
Executing task 4 by pool-1-thread-1
Task 4 completed by pool-1-thread-1
Executing task 5 by pool-1-thread-1
Task 5 completed by pool-1-thread-1

Example 2: Ensuring Sequential Task Execution

In this example, we use a single-thread executor to ensure tasks that need to be executed sequentially are handled in the correct order.

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

public class SequentialTaskExecutionExample {
    public static void main(String[] args) {
        // Create a single-thread executor
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // Submit tasks that need to be executed sequentially
        executor.submit(() -> {
            System.out.println("Task A started");
            try {
                Thread.sleep(1000); // Simulate task execution
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task A completed");
        });

        executor.submit(() -> {
            System.out.println("Task B started");
            try {
                Thread.sleep(1000); // Simulate task execution
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task B completed");
        });

        executor.submit(() -> {
            System.out.println("Task C started");
            try {
                Thread.sleep(1000); // Simulate task execution
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task C completed");
        });

        // Shutdown the executor
        executor.shutdown();
    }
}

Output:

Task A started
Task A completed
Task B started
Task B completed
Task C started
Task C completed

Example 3: Using Single-Thread Executor for Logging

In this example, we use a single-thread executor to ensure that logging tasks are executed sequentially, avoiding potential concurrency issues.

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

public class LoggingExample {
    public static void main(String[] args) {
        // Create a single-thread executor for logging
        ExecutorService logger = Executors.newSingleThreadExecutor();

        // Simulate logging from different threads
        for (int i = 0; i < 5; i++) {
            final int logNumber = i + 1;
            new Thread(() -> {
                logger.submit(() -> {
                    System.out.println("Log entry " + logNumber + " by " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(500); // Simulate logging delay
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }).start();
        }

        // Shutdown the logger after a delay
        new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.shutdown();
            System.out.println("Logger shutdown");
        }).start();
    }
}

Output:

Log entry 1 by pool-1-thread-1
Log entry 2 by pool-1-thread-1
Log entry 3 by pool-1-thread-1
Log entry 4 by pool-1-thread-1
Log entry 5 by pool-1-thread-1
Logger shutdown

Conclusion

The Executors.newSingleThreadExecutor() method in Java is used for creating an executor that uses a single worker thread to execute tasks sequentially. It is particularly useful when tasks need to be executed in a strict order, such as in logging or sequential processing scenarios.

Comments