• Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All
  • About
Java | Single Thread Executor
  1. Single Thread Executor
  2. Example (1): ExecutorService::execute(Runnable)
  3. Example (2) - Synchronous execution: ExecutorService::submit(Callable)
  4. Example (3) - Asynchronous execution: ExecutorService::submit(Callable)

  1. Single Thread Executor
    The ExecutorService framework provides a higher-level replacement for working with threads directly. It manages thread pools, handles thread lifecycle (creation, scheduling, and cleanup), and provides various execution strategies.

    The Executors.newSingleThreadExecutor creates a single-threaded executor that executes tasks sequentially in a dedicated thread, making it ideal for tasks that need to be processed in order or when you want to avoid thread contention.

    Here's the minimal dependencies needed in order for the following examples to work ("pom.xml" file):
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.17.0</version>
    </dependency>
    Note: The Apache Commons Lang3 dependency is included for the BasicThreadFactory class, which provides convenient thread naming and daemon thread configuration. While Java's built-in Executors.newSingleThreadExecutor works without additional dependencies, using a custom ThreadFactory allows better thread management and debugging.
  2. Example (1): ExecutorService::execute(Runnable)
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.IntStream;
    
    import org.apache.commons.lang3.concurrent.BasicThreadFactory;
    
    public class MainClass {
        public static void main(String[] args) throws InterruptedException {
            final String namingPattern = "_newSingleThreadExecutor_runnable";
    
            final BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder();
    
            final BasicThreadFactory basicThreadFactory = builder.namingPattern(namingPattern).daemon(true).build();
    
            final ExecutorService executorService = Executors.newSingleThreadExecutor(basicThreadFactory);
    
            IntStream.iterate(0, i -> i + 1).limit(5).forEach(
                    t -> executorService.execute(() -> System.out.println(Thread.currentThread().getName() + ": " + t)));
    
            executorService.awaitTermination(100l, TimeUnit.MILLISECONDS);
    
            executorService.shutdown();
        }
    }
    Output:
    _newSingleThreadExecutor_runnable: 0
    _newSingleThreadExecutor_runnable: 1
    _newSingleThreadExecutor_runnable: 2
    _newSingleThreadExecutor_runnable: 3
    _newSingleThreadExecutor_runnable: 4
    The execute() method accepts a Runnable and returns void. The daemon (background) thread setting ensures the thread won't prevent JVM shutdown. Note that awaitTermination() should be called after shutdown() for proper cleanup. It blocks until all tasks complete after shutdown, or timeout occurs, or current thread is interrupted. You should consider timeout values for awaitTermination() based on your application's requirements.

    Always shutdown ExecutorService instances to prevent resource leaks. You can use shutdownNow() if you need to interrupt running tasks; you should handle InterruptedException properly.
  3. Example (2) - Synchronous execution: ExecutorService::submit(Callable)
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    import org.apache.commons.lang3.concurrent.BasicThreadFactory;
    
    public class MainClass {
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            final String namingPattern = "_newSingleThreadExecutor_callable_sync";
    
            final BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder();
    
            final BasicThreadFactory basicThreadFactory = builder.namingPattern(namingPattern).daemon(true).build();
    
            final ExecutorService executorService = Executors.newSingleThreadExecutor(basicThreadFactory);
    
            // Callable - synchronous
            {
                Callable<Integer> callable = () -> {
                    System.out.println(Thread.currentThread().getName() + ": Callable Sync...");
                    return 1;
                };
    
                Future<Integer> task = executorService.submit(callable);
    
                Integer result = task.get();
    
                System.out.println(result);
            }
    
            executorService.shutdown();
        }
    }
    Output:
    _newSingleThreadExecutor_callable_sync: Callable Sync...
    1
    Unlike Runnable, Callable can return a value and throw checked exceptions. The submit() method returns a Future<T> object that represents the result of the computation. Calling get() on the Future blocks the current thread until the task completes, making this synchronous execution.
  4. Example (3) - Asynchronous execution: ExecutorService::submit(Callable)
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    import org.apache.commons.lang3.concurrent.BasicThreadFactory;
    
    public class MainClass {
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            final String namingPattern = "_newSingleThreadExecutor_callable_async";
    
            final BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder();
    
            final BasicThreadFactory basicThreadFactory = builder.namingPattern(namingPattern).daemon(true).build();
    
            final ExecutorService executorService = Executors.newSingleThreadExecutor(basicThreadFactory);
    
            // Callable - asynchronous
            {
                Callable<Void> callable = () -> {
                    System.out.println(Thread.currentThread().getName() + ": Callable Async...");
                    return null;
                };
    
                executorService.submit(callable);
            }
    
            executorService.awaitTermination(100l, TimeUnit.MILLISECONDS);
    
            executorService.shutdown();
        }
    }
    Output:
    _newSingleThreadExecutor_callable_async: Callable Async...
    This example demonstrates asynchronous execution. The submit() call returns immediately without waiting for the task to complete. You would typically want to store the returned Future to check task completion status or handle exceptions.
© 2025  mtitek