Guide to Java 8 Concurrency API using Executors

Concurrency API

Working with the Thread class in Java can be very tedious and error-prone. Due to this reason, Concurrency API was introduced back in 2004 with the release of Java 5 and then enhanced with every new Java release.The API is located in package java.util.concurrent. It contains a set of classes that make it easier to develop concurrent (multithreaded) applications in Java. 

The executor services are one of the most important part of the Concurrency API. With the help of this guide, you can learn how to execute code in parallel via tasks and executor services in Java 8.

ExecutorService

The Concurrency API introduces the concept of an ExecutorService as a higher level replacement for working with threads directly.

Executors are capable of managing a pool of threads, so we do not have to manually create new threads and run tasks in an asynchronous fashion.
Have a look at a simple Java ExecutorService:

[sourcecode language=”java”]
ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {

String threadName = Thread.currentThread().getName();

System.out.println(“Hello ” + threadName);

});
[/sourcecode]

Here, It submits a Runnable task for execution and returns a Future representing that task. Since Runnable is a functional interface we are utilizing Java 8 lambda expressions to print the current threads name to the console.

ExecutorService Implementation

Since ExecutorService is an interface, it has to be implemented in order to make any use of it. The ExecutorService has the following implementation in the java.util.concurrent package:

  • ThreadPoolExecutor
  • ScheduledThreadPoolExecutor

Executors factory class can also be used to create executor instances.

For eg.-

[sourcecode language=”java”]

ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newFixedThreadPool(5);

[/sourcecode]

Delegating tasks to ExecutorService

Below are few of the different ways that can be used to delegate tasks for execution to an ExecutorService:

  • execute(Runnable command)
  • submit(Callable task)
  • submit(Runnable task)
  • invokeAny(Collection<? extends Callable<T>> tasks)
  • invokeAll(Collection<? extends Callable<T>> tasks)

execute(Runnable command)

This method takes a java.lang.Runnable object, and executes it asynchronously.

[sourcecode language=”java”]

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -&gt; {

String threadName = Thread.currentThread().getName();
&nbsp;System.out.println(“Hello ” + threadName);
});

[/sourcecode]

submit(Callable task) and submit(Runnable task)

The submit(Runnable task) method takes a Runnable implementation and returns a Future object. which can be used to check if the Runnable as finished executing.

[sourcecode language=”java”]

Runnable task=()-&gt;{
System.out.println(“runnable task”);
};

ExecutorService executorService= Executors.newSingleThreadExecutor();
Future future= executorService.submit(task);
System.out.println(“value – “+future.get()); //returns null if the task has finished successfully

[/sourcecode]

Callables are functional interfaces but unlike Runnable they return a value. submit(callable task) method takes a Callable implementation

[sourcecode language=”java”]

Callable&lt;String&gt; task = () -&gt; “task 1 “;
ExecutorService executorService= Executors.newSingleThreadExecutor();
Future future= executorService.submit(task);
System.out.println(“value – “+future.get()); //returns task1

[/sourcecode]

invokeAll(Collection<? extends Callable<T>> tasks)

This method supports batch submitting of multiple callables at once. It accepts a collection of callables and returns a list of futures.

[sourcecode language=”java”]

ExecutorService executor = Executors.newFixedThreadPool(1);

List&lt;Callable&lt;String&gt;&gt; callables = Arrays.asList(
() -&gt; “t1”,
() -&gt; “t2”
);

executor.invokeAll(callables)
.stream()
.map(future -&gt; {
try {
return future.get();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
})
.forEach(System.out::println);

[/sourcecode]

invokeAny(Collection<? extends Callable<T>> tasks)

This method works slightly different to invokeAll(). Instead of returning future objects it blocks until the first callable terminates and returns the result of that callable.

[sourcecode language=”java”]

ExecutorService executor = Executors.newWorkStealingPool();

List&lt;Callable&lt;String&gt;&gt; callables = Arrays.asList(
()-&gt;”task 1 completed”,

[/sourcecode]

ExecutorService shut down

ExecutorService provides two methods for this purpose:

  • shutdown() waits for currently running tasks to finish
  • shutdownNow() interrupts all running tasks and shut the executor down immediately.

References


KNOLDUS-advt-sticker

Written by 

Himani is a Software Consultant, having experience of more than 2.5 years. She is very dedicated, hardworking and focussed. She is Familiar with C#, C++, C , PHP, Scala and Java and has interest in Functional programming. She is very helpful and loves to share her knowledge. Her hobbies include reading books and cooking.

1 thought on “Guide to Java 8 Concurrency API using Executors

Leave a Reply

%d bloggers like this: