ExecutorService

Java ExecutorService Example – Tutorial

Java ExecutorService is an interface that extends Executor class and represents an asynchronous execution. Executor service provides us mechanisms to manage the end and detect progress of the asynchronous tasks.

In this example, we are going to see some basic functionalities of ExecutorService, as well as handle the Future object, the result of asynchronous computation.

1. Runnable vs Callable

The Callable interface is similar to Runnable, in that both are designed for classes whose instances are potentially executed by another thread. However Runnable interface cannot do everything that Callable does:

  • Callable instance returns a result, whereas a Runnable instance does not.
  • Callable instance may throw checked exceptions, whereas as Runnable instance can not.

2. Create the Runnable

We are going to create a Runnable that is intended to be executed by the ExecutorService. Create a java class named myThread and paste the following code.

myThread.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.javacodegeeks.core.concurrency.executorservicetest;
 
public class MyThread implements Runnable {
     
    private String myName;
    private int count;
    private final long timeSleep;
 
    MyThread(String name, int newcount, long newtimeSleep) {
        this.myName = name;
        this.count = newcount;
        this.timeSleep = newtimeSleep;
    }
     
    @Override
    public void run() {
        // TODO Auto-generated method stub
 
        int sum = 0;
        for (int i = 1; i <= this.count; i++) {
            sum = sum + i;
        }
        System.out.println(myName + " thread has sum = " + sum +
                " and is going to sleep for " + timeSleep);
        try {
            Thread.sleep(this.timeSleep);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
}

The functionality of the Runnable is very simple. It computes a sum from the giving argument and it sleeps for a specified time.

3. Code the ExecutorService in Java

In this example we will use a factor method of ExecutorService that creates a thread pool of fixed number of threads. For this reason, newFixedThreadPool() method is used where we specify the number of threads in the pool. To execute the thread, we can use either execute() method or submit(), where both of them take Runnable as a parameter. execute() method is depending on the implementation of the Executor class and may perform the Runnable in a new thread, in a pooled thread, or in the calling thread. submit() method extends execute(), by returning a Future that represents the submitting task.

The Future can be used to indicate the termination of execution of the thread. For instance, get() method waits for the completion of the computation. If the returning value is null, the task has finished correctly. Otherwise, cancel() method can be called in order to end the execution of this task. It is worth to mention that for bulk or a collection of thread execution, invokeAll() and invokeAny() are used respectively, although there are not used in this example.

To close down the ExecutorService, there are many methods that can be used. In our example we use shutdown() method, in which the submitted tasks are executed before the shutting down but new tasks can not be accepted. Another approach is shutdownNow() method, which stops the executing tasks, pause the waiting ones and returns the list of the awaiting ones. Moreover, awaitTermination() can be used in order to wait until all threads are terminated.

For further understanding of the main functionality of ExecutorService, have a look at the code below. Create ExecutorServiceTest.java file and paste the following.

ExecutorServiceTest.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.javacodegeeks.core.concurrency.executorservicetest;
 
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
 
public class ExecutorServiceTest {
 
    private static Future taskTwo = null;
    private static Future taskThree = null;
     
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        // execute the Runnable
        Runnable taskOne = new MyThread("TaskOne", 2, 100);
        executor.execute(taskOne);
        for(int i = 0; i < 2; i++) {
            // if this task is not created or is canceled or is completed
            if ((taskTwo == null) || (taskTwo.isDone()) || (taskTwo.isCancelled())) {
                // submit a task and return a Future
                taskTwo = executor.submit(new MyThread("TaskTwo", 4, 200));
            }
     
            if ((taskThree == null) || (taskThree.isDone()) || (taskThree.isCancelled())) {
                taskThree = executor.submit(new MyThread("TaskThree", 5, 100));
            }
            // if null the task has finished
            if(taskTwo.get() == null) {
                System.out.println(i+1 + ") TaskTwo terminated successfully");
            } else {
                // if it doesn't finished, cancel it
                taskTwo.cancel(true);
            }
            if(taskThree.get() == null) {
                System.out.println(i+1 + ") TaskThree terminated successfully");
            } else {
                taskThree.cancel(true);
            }
        }
        executor.shutdown();
        System.out.println("-----------------------");
        // wait until all tasks are finished
        executor.awaitTermination(1, TimeUnit.SECONDS);
        System.out.println("All tasks are finished!");
     
    }
 
}

Now you can see the output of the execution.

Output

TaskOne thread has sum = 3 and is going to sleep for 100
TaskTwo thread has sum = 10 and is going to sleep for 200
TaskThree thread has sum = 15 and is going to sleep for 100
1) TaskTwo terminated successfully
1) TaskThree terminated successfully
TaskTwo thread has sum = 10 and is going to sleep for 200
TaskThree thread has sum = 15 and is going to sleep for 100
2) TaskTwo terminated successfully
2) TaskThree terminated successfully
-----------------------
All tasks are finished!

4. The ScheduledExecutorService Interface

ScheduledExecutorService is java.util.concurrent.ExecutorService thus it inherits all the functional abstractions from ExecutorService interface (and its super interfaces!); nevertheless, the difference being, ScheduledExecutorService can “schedule commands to run after a given delay, or to execute periodically” (Source).

The public API to use ScheduledExecutorService is pretty straightforward. We can “schedule” a repetitive or delayed task encapsulated in a java.lang.Runnable or java.util.concurrent.Callable instance with ScheduledExecutorService configuring the delays. It is obvious that a Runnable task would be non result bearing one and Callable would produce some result.

An instance of ScheduledThreadPoolExecutor can be retrieved from the convenient factory API, java.util.concurrent.Executors.newScheduledThreadPool(int corePoolSize) or its overloaded version Executors.newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory). In the subsequent sections, we will demonstrate these APIs through the way of an example.

5. ExecutorService vs Fork/Join Pool

Each of these APIs are targeted to fulfil respective business needs of your application.

ExecutorService

ExecutorService is an interface that extends Executor class and represents an asynchronous execution. It provides us mechanisms to manage the end and detect progress of the asynchronous tasks.

  • Executor service manage thread in asynchronous way
  • Use callable to get the return result after thread completion
  • Manage allocation of work to free thread and resale completed work from thread for assigning new work automatically
  • Better communication between threads
  • invokeAll and invokeAny give more control to run any or all thread at once
  • shutdown provide capability for completion of all thread assigned work
  • Scheduled Executor Services provide methods for producing repeating invocations of runnables and callables Hope it will help you

ForkJoinPool

Fork-Join framework is an extension to Executor service framework to particularly address ‘waiting’ issues in recursive multi-threaded programs. In fact, the new Fork-Join framework classes all extend from the existing classes of the Executor framework. ForkJoinPool is for many, dependent, task-generated, short, hardly ever blocking (i.e. compute-intensive) tasks

  • parallelism – the parallelism level. For default value, use Runtime.availableProcessors()
  • factory – the factory for creating new threads. For default value, use defaultForkJoinWorkerThreadFactory
  • handler – the handler for internal worker threads that terminate due to unrecoverable errors
  • asyncMode – if true, establishes local first-in-first-out scheduling mode for forked tasks that are never joined.

6. Download the source code

This was an example of ExecutorService in Java.

Download
Download the source code of this example: Java ExecutorService Example – Tutorial

Last updated on May 25th, 2020

Katerina Zamani

Katerina has graduated from the Department of Informatics and Telecommunications in National and Kapodistrian University of Athens (NKUA) and she attends MSc courses in Advanced Information Systems at the same department. Currently, her main academic interests focus on web applications, mobile development, software engineering, databases and telecommunications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Mohit
Mohit
6 years ago

Hi,
Thanks for such an useful topic.
In one interview I face the question that, in what scenario if we declare thread pool along with connection pooling in hibernate will be helpful? Will it work parley?

Mohit
Mohit
6 years ago

*in parallel?

Back to top button