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.<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.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: 4The
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.shutdownNow()
if you need to interrupt running tasks; you should handle InterruptedException
properly.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... 1Unlike
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.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.