The Java programming language works very efficiently with multi-threaded applications that require simultaneous execution of tasks in a thread. It is difficult for an application to execute a large number of threads simultaneously. To work around this issue, Java comes with ExecutorService.
What is ExecutorService?
ExecutorService is a framework provided by JDK, which can simplify the execution of tasks in asynchronous mode. Generally speaking, ExecutorService automatically provides a pool of threads and API for assigning tasks to it and also provides a submit() method that can accept both runnable and callable objects.
Instantiating ExecutorService
1. Factory Methods of the Executors Class
The finest way to create ExecutorService is to use one of the factory methods of the Executors class.
For example, this code will create a thread-pool with 10 threads:
ExecutorService executor = Executors.newFixedThreadPool(10);
2. Directly Create an ExecutorService
Because ExecutorService is an interface, so an instance can be used for any implementations. There are many implementations to choose from in the java.util.concurrent package or you can create your own.
For example, The ThreadPoolExecutor class contains some constructors that can be used to configure an executor service and internal pool services.
ExecutorService executorService =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>())
Working with Executor Service
ExecutorService can execute Runnable and Callable tasks. here i am using lambda expressions instead of anonymous inner classes:
Runnable runnableTask = () -> {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Callable<String> callableTask = () -> {
TimeUnit.MILLISECONDS.sleep(300);
return "Task's execution";
};
List<Callable<String>> callableTasks = new ArrayList<>();
callableTasks.add(callableTask);
callableTasks.add(callableTask);
callableTasks.add(callableTask);
Several methods can be used to the assigned task to the ExecutorService,
1. execute () - It is inherited from the Executor interface, execute() method is void, and it doesn't give any possibility to get the result of task's execution or to check the task's status (is it running or executed).
executorService.execute(runnableTask);
2. submit () - submits a Callable or a Runnable task to an ExecutorService it will returns a result of type Future.
Future<String> future =
executorService.submit(callableTask);
3. invokeAny () - Assigns a collection of tasks to an ExecutorService, causing each to be executed, and returns the result of a successful execution of one task (if there was a successful execution).
String result = executorService.invokeAny(callableTasks);
4. invokeAll () - Assigns a collection of tasks to ExecutorService, which leads to each execution, and returns the result of all task executions as a list of Future type objects.
List<Future<String>> futures = executorService.invokeAll(callableTasks);
5. shutdown () - This method does not cause immediate destruction of ExecutorService. It will make ExecutorService stop accepting new tasks and close after all running threads have finished their current work.
executorService.shutdown();
6. shutdownNow () - The shutdownNow() method attempts to destroy ExecutorService immediately, but it does not guarantee that all running threads are stopped at the same time. This method returns the list of tasks waiting to be processed. The developer needs to decide what to do with these tasks.
List<Runnable> notExecutedTasks = executorService.shutDownNow();
Thank You