🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
Introduction
The ExecutorService interface in Java is part of the java.util.concurrent package and provides a framework for managing a pool of threads and executing tasks asynchronously. It decouples task submission from the mechanics of how each task will be run, including details of thread use, scheduling, etc. ExecutorService is typically used to manage and control the execution of tasks, making it easier to handle multithreading in Java.
Table of Contents
- Overview of ExecutorService
- Creating an ExecutorService
- Submitting Tasks to ExecutorService
- Shutting Down ExecutorService
- Example: Using ExecutorService
- Handling Callable and Future with ExecutorService
- Example: ScheduledExecutorService
- Conclusion
1. Overview of ExecutorService
ExecutorService is a subinterface of Executor that provides methods to manage the lifecycle of threads and to perform asynchronous task execution. Some of the key methods include:
submit(): Submits a task for execution and returns aFuturerepresenting the task.invokeAll(): Executes a collection of tasks and returns a list ofFutureobjects.invokeAny(): Executes a collection of tasks and returns the result of one of the tasks.shutdown(): Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.shutdownNow(): Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
2. Creating an ExecutorService
You can create an ExecutorService using the Executors factory methods, such as:
newFixedThreadPool(int nThreads): Creates a thread pool with a fixed number of threads.newCachedThreadPool(): Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.newSingleThreadExecutor(): Creates an executor that uses a single worker thread.
Example:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceExample {
public static void main(String[] args) {
// Creating a fixed thread pool with 2 threads
ExecutorService executorService = Executors.newFixedThreadPool(2);
// Submit tasks to the executor service
executorService.submit(() -> System.out.println("Task 1 executed by " + Thread.currentThread().getName()));
executorService.submit(() -> System.out.println("Task 2 executed by " + Thread.currentThread().getName()));
executorService.submit(() -> System.out.println("Task 3 executed by " + Thread.currentThread().getName()));
// Shutdown the executor service
executorService.shutdown();
}
}
Output:
Task 1 executed by pool-1-thread-1
Task 2 executed by pool-1-thread-2
Task 3 executed by pool-1-thread-1
Explanation:
- A fixed thread pool with 2 threads is created.
- Three tasks are submitted to the executor service.
- The tasks are executed by the threads in the pool.
- The executor service is shut down.
3. Submitting Tasks to ExecutorService
Tasks can be submitted to the ExecutorService using the submit method. You can submit Runnable or Callable tasks.
Example:
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;
public class SubmitTasksExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
// Submitting a Runnable task
Future<?> future1 = executorService.submit(() -> {
System.out.println("Runnable task executed by " + Thread.currentThread().getName());
});
// Submitting a Callable task
Future<String> future2 = executorService.submit(() -> {
System.out.println("Callable task executed by " + Thread.currentThread().getName());
return "Result from Callable task";
});
try {
// Getting the result of the Callable task
String result = future2.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
Output:
Runnable task executed by pool-1-thread-1
Callable task executed by pool-1-thread-2
Result from Callable task
Explanation:
- A fixed thread pool with 2 threads is created.
- A
Runnabletask and aCallabletask are submitted to the executor service. - The
Runnabletask does not return a result. - The
Callabletask returns a result which is retrieved using theFutureobject.
4. Shutting Down ExecutorService
It's important to shut down the ExecutorService to release the resources it holds. You can shut it down gracefully or forcefully.
Graceful Shutdown:
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
Forceful Shutdown:
executorService.shutdownNow();
5. Example: Using ExecutorService
Let's create a complete example that demonstrates how to create an ExecutorService, submit tasks, and shut it down.
Example:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Task implements Runnable {
private final String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Task " + name + " is being executed by " + Thread.currentThread().getName());
try {
Thread.sleep(2000); // Simulate long-running task
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ExecutorServiceDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
Task task = new Task("Task " + i);
executorService.submit(task);
}
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
System.out.println("All tasks are finished.");
}
}
Output:
Task Task 1 is being executed by pool-1-thread-1
Task Task 2 is being executed by pool-1-thread-2
Task Task 3 is being executed by pool-1-thread-3
Task Task 4 is being executed by pool-1-thread-1
Task Task 5 is being executed by pool-1-thread-2
All tasks are finished.
Explanation:
- A fixed thread pool with 3 threads is created.
- Five tasks are submitted to the executor service.
- Each task prints its name and the name of the thread executing it.
- The executor service is shut down gracefully, waiting for up to 60 seconds for tasks to complete.
6. Handling Callable and Future with ExecutorService
You can use the Callable interface with ExecutorService to handle tasks that return results and may throw exceptions.
Example:
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;
class CallableTask implements Callable<String> {
private final String name;
public CallableTask(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
System.out.println("Task " + name + " is being executed by " + Thread.currentThread().getName());
Thread.sleep(2000); // Simulate long-running task
return "Result of " + name;
}
}
public class CallableFutureDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Future<String> future1 = executorService.submit(new CallableTask("Task 1"));
Future<String> future2 = executorService.submit(new CallableTask("Task 2"));
try {
System.out.println(future1.get());
System.out.println(future2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
Output:
Task Task 1 is being executed by pool-1-thread-1
Task Task 2 is being executed by pool-1-thread-2
Result of Task 1
Result of Task 2
Explanation:
- The
CallableTaskclass implements theCallableinterface and returns a result. - Two
Callabletasks are submitted to the executor service. - The results of the tasks are retrieved using the
Futureobjects.
7. Example: ScheduledExecutorService
The ScheduledExecutorService interface extends ExecutorService and provides methods to schedule tasks to run after a delay or to execute periodically.
Example:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
class ScheduledTask implements Runnable {
private final String name;
public
ScheduledTask(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Task " + name + " is being executed by " + Thread.currentThread().getName());
}
}
public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
scheduledExecutorService.schedule(new ScheduledTask("Task 1"), 5, TimeUnit.SECONDS);
scheduledExecutorService.schedule(new ScheduledTask("Task 2"), 10, TimeUnit.SECONDS);
scheduledExecutorService.shutdown();
}
}
Output:
Task Task 1 is being executed by pool-1-thread-1
Task Task 2 is being executed by pool-1-thread-2
Explanation:
- A scheduled thread pool with 2 threads is created.
- Two tasks are scheduled to run after a delay of 5 and 10 seconds, respectively.
- The tasks print their name and the name of the thread executing them.
8. Conclusion
The ExecutorService interface in Java provides a powerful framework for managing and executing asynchronous tasks. By using ExecutorService, you can simplify the handling of multithreading, improve resource management, and enhance the performance of your applications. This tutorial covered the basics of creating an ExecutorService, submitting tasks, handling Callable and Future, and using ScheduledExecutorService.
Happy coding!
Comments
Post a Comment
Leave Comment