Guide to Java 8 concurrency using Executors


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:

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {

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

System.out.println("Hello " + threadName);

});

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.-


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

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.


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

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

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.


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

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


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

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.


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);

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.


ExecutorService executor = Executors.newWorkStealingPool();

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

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

About Himani Arora

Software consultant at Knoldus Software LLP.
This entry was posted in Java, Scala and tagged , , , , . Bookmark the permalink.

One Response to Guide to Java 8 concurrency using Executors

  1. Prabhat Kashyap says:

    Reblogged this on Prabhat Kashyap – Scala-Trek.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s