#
Executor Service
This tutorial explains how to use the Executor Service in Java.
The Java ExecutorService is the interface which allows us to execute tasks on threads asynchronously. It defines a pool of threads to be used.
How you create an ExecutorService depends on the implementation you use.
// It create a pool for a single thread
ExecutorService es1 = Executors.newSingleThreadExecutor();
// It create a thread pool with maximum 10 threads
ExecutorService es2 = Executors.newFixedThreadPool(10);
// It create a thread pool with maximum 10 threads. The tasks could be scheduled using a pattern.
ScheduledExecutorService es3 = Executors.newScheduledThreadPool(10);
Take a look at the following example and read carefully the comment in the code.
package com.exampe.java;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws InterruptedException, ExecutionException {
SpringApplication.run(DemoApplication.class, args);
System.out.println("--------------------------------------------");
Runnable task1 = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println("Task #1 is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
Callable<Integer> task2 = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println("Task #2 is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return 10;
};
Callable<Integer> task3 = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println("Task #3 is running");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return 10;
};
ExecutorService es1 = Executors.newFixedThreadPool(10);
// Run a task without returned value.
es1.execute(task1);
// Run a task. The task has a result kept in the future object
Future f1 = es1.submit(task2);
//Print the result of the task
System.out.println("f1= "+f1.get());
List<Callable<Integer>> taskList = new ArrayList<>();
taskList.add(task2);
taskList.add(task3);
// The task2 & task3 will run simultaneously. The first returned resul will be taken
// by the "result" variable.
Integer result = es1.invokeAny(taskList);
System.out.println("result="+result);
// Run in parallel a list of tasks and keep the result returned by each of them
// In this case I print the result of the first task in the list ("task2")
List<Future<Integer>> result2 = es1.invokeAll(taskList);
System.out.println("result2="+result2.get(0).get());
// Stop the Executor Service
es1.shutdown();
System.out.println("--------------------------------------------");
}
}
Info
shutdown()
- shutdowns the Executor Service - no new tasks are accepted, it waits for previously submitted tasks to complete execution.shutdownNow()
- forcibly, attempts to stop all actively executing tasks, and returns a list of the tasks that were awaiting execution.
If you want to have more control of the thread pool, you can use ThreadPoolExecutor
class
(or ThreadPoolTaskExecutor class in Spring).
ThreadPoolExecutor class is an implementation of the ExecutorService interface.
A ThreadPoolExecutor will automatically adjust the pool size according to the bounds, set by corePoolSize and maximumPoolSize.
Take a look at the following methods:
getPoolSize()
getCorePoolSize()
getMaximumPoolSize()
Info
- The Spring Framework provides abstractions for the asynchronous execution and scheduling of tasks with the
TaskExecutor
andTaskScheduler
interfaces, respectively. - Spring’s TaskExecutor interface is identical to the java.util.concurrent.Executor interface.
- Spring includes a number of pre-built implementations of TaskExecutor, such as: SyncTaskExecutor, ThreadPoolTaskExecutor, ConcurrentTaskExecutor.
In any Java applications we have:
- Executor interface - we have
void execute(Runnable command)
method => you can run Async call in a thread pool - ExecutorService interface extends Executor and add more method, including "submit()", "invokeAny()", "shutdown()". More information we can have here
- Executors class - a factory and utility methods for Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, and Callable interfaces defined in this package. The most used methods perhaps are: Executors.newSingleThreadExecutor(), Executors.newFixedThreadExecutor(), Executors.newScheduledThreadExecutor(). More information you can have here.
In Spring Boot applications "taskExecutor" Bean is the default TaskExecutor. If not defined, and we have more than 1 task executors we need to define one as @Primary to be the default task executor.
If no executor is created one will be created automatically.