Java Executors
The java.util.concurrent package provides a powerful toolkit for doing just that, with Executors playing a central role. This article dives into the world of Executors, offering examples and advanced tips to harness their full potential.
Introduction to Executors
At its core, an Executor is an interface that represents an object that executes provided tasks. Executors decouple task submission from execution policy, allowing developers to manage thread use and task execution without delving into the complexities of thread management.
The Executor Framework
The Executor framework includes several key interfaces and classes:
Basic Examples
Let's explore some basic examples to get started with Executors.
Creating a Single Thread Executor
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("Hello " + threadName);
});
executor.shutdown();
This example creates an executor that executes a single task in a single background thread.
Fixed Thread Pool
int numberOfThreads = 4;
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("Executing task in " + threadName);
});
}
executor.shutdown();
Here, a pool of threads is created to execute multiple tasks concurrently, up to the number of available threads.
领英推荐
Advanced Usage
As you grow more comfortable with basic Executors, consider these advanced techniques to further optimize your concurrent Java applications.
Custom Thread Factories
Custom thread factories can be used with Executors to customize the threads used in the thread pool, such as setting custom names for easier debugging.
ThreadFactory customThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("CustomPool-%d")
.build();
ExecutorService executor = Executors.newFixedThreadPool(2, customThreadFactory);
Handling Results with Future
ExecutorService can return a Future object to track the progress and result of an asynchronous computation.
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {
Thread.sleep(2000);
return "Result of the asynchronous computation";
});
String result = future.get(); // Blocks until the result is available.
System.out.println(result);
executor.shutdown();
Scheduled Execution
ScheduledExecutorService allows you to schedule tasks to run after a specified delay or to execute periodically.
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> System.out.println("Scheduling: " + System.nanoTime());
int initialDelay = 3;
int periodicDelay = 1;
scheduler.scheduleAtFixedRate(task, initialDelay, periodicDelay, TimeUnit.SECONDS);
Tips for Advanced Users
Conclusion
Java's Executor framework simplifies concurrent programming by abstracting thread management and providing a flexible mechanism for executing tasks asynchronously. By mastering Executors and incorporating advanced practices into your development workflow, you can significantly enhance the performance and reliability of your Java applications.