Executor Service Framework in Java

Posted By : Rahul Sarkar | 30-Jul-2018

ExecutorService is a framework provided by the JDK that simplifies task execution in asynchronous mode. In general, ExecutorService automatically provides a set of threads and APIs to assign tasks to it.


1. Instantiate ExecutorService


1.1.Executor-class factory method


The easiest way to create an ExecutorService is to use one of the factory methods of the executor class.

For example, the following line of code will create a child process group with 10 child processes:

ExecutorService executor = Executors.newFixedThreadPool(10);

There are other factory methods that can create a predefined ExecutorService that meets a specific use case. To find the best way to meet your needs, please refer to the official Oracle documentation.

 

1.2. Create an ExecutorService directly


Because the ExecutorService is an interface, you can use an instance of any of its implementations. There are several implementations to choose from in the java.util.concurrent package, or you can create your own implementation.

For example, the ThreadPoolExecutor class has constructors that can be used to configure the executor service and its internal groups.

ExecutorService executorService =
       new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
       new LinkedBlockingQueue<Runnable>());

You may notice that the previous code is very similar to the source code of the factory method newSingleThreadExecutor(). For most cases, no detailed manual configuration is required.

 

2. Assign tasks to ExecutorService


ExecutorService can perform executable and callable tasks. To simplify this article, two original tasks will be used. Note that lambda expressions are used here instead of anonymous inner classes:

Runnable runnableTask = () -> {
    try {
        TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};
 
Callable callableTask = () -> {

    TimeUnit.MILLISECONDS.sleep(300);
    return "Task's execution";
};
 
List> callableTasks = new ArrayList<>();
callableTasks.add(callableTask);
callableTasks.add(callableTask);
callableTasks.add(callableTask);

There are several ways to assign tasks to ExecutorService, including execute() inherited from the Executor interface, and submit(), invokeAny(), invokeAll().

The execute() method is null and there is no chance to get the result of the task execution or verify the state of the task (it is running or executing).

executorService.execute(runnableTask);

Submit() sends an invokable or executable task to the ExecutorService and returns the result of the Future type.

 

Future future = 
  executorService.submit(callableTask);

  
invokeAny() assigns a set of tasks to the ExecutorService, causing each task to execute and return the result of the successful execution of the task (if successful).


String result = executorService.invokeAny(callableTasks);
invokeAll() assigns a set of tasks to the ExecutorService, causing each task to execute and returning the results of all task executions in the form of a list of objects of the Future type.

 

List > futures = executorService.invokeAll(callableTasks);

Now, before proceeding, you must analyze two things: turn off the ExecutorService and handle future return types.

 

3. Close ExecutorService


Typically, ExecutorService is not automatically destroyed when there are no tasks to process. He will be alive waiting for the new job to be completed.

This can be useful in some situations; for example, if an application needs to handle irregularly occurring tasks, or if you don't know the number of tasks at compile time.

On the other hand, the application may end, but it won't stop because the waiting ExecutorService will cause the JVM to continue running.

To successfully close the ExecutorService, we have API shutdown() and shutdownNow().

The shutdown() method does not immediately cause the destruction of the ExecutorService. It will cause the ExecutorService to stop accepting new tasks and close after all running threads have completed the current job.

executorService.shutdown();

The shutdownNow() method attempts to destroy the ExecutorService immediately but does not guarantee that all running threads will stop at the same time. This method returns a list of tasks waiting to be processed. It is up to the developer to decide how to handle these tasks.

List notExecutedTasks = executorService.shutDownNow();

A good way to turn off ExecutorService (also recommended by Oracle) is to use two methods in conjunction with the awaitTermination() method. Using this method, the ExecutorService will first stop executing new tasks and wait for a specific time period to complete all tasks. If the time expires, execution stops immediately:

executorService.shutdown();
try {
    if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
        executorService.shutdownNow();
    } 
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

 

Thanks,

About Author

Author Image
Rahul Sarkar

Rahul is an intellectual web app developer, he has good knowledge of C, Java, Java Script, Jquery. Apart from this he likes to travel and explore new places.

Request for Proposal

Name is required

Comment is required

Sending message..