Executing operations one after another is easy. However, sometimes we desire more - parallelism. Are you sure you know how to execute tasks in parallel in Java? If not, let me show you how to start multiple threads with ExecutorService, give them some tasks and wait for the result.

# One thread execution

A sample problem that I will solve is to sum all integers from 1 to 100. That is extremely easy job to do. Although there multiple approaches, I will use one of them. This task can be done by one simple method.

private int sum(int from, int to) {

return IntStream.rangeClosed(from, to).sum();

}

It uses Java streams to sum the integers from a specific range. *IntStream.rangeClosed* creates a stream of consecutive integers from a range. The *sum* operation sums all numbers from the stream and returns the total.

To print a sum of integers from 1 to 100, I run the following code:

System.*out*.println(sum(1, 100));

The result is 5050

*assertEquals*(5050, sum(1, 100));

but it does not matter.

# Splitting one task to smaller independent tasks

Of course, that was easy. But we can play more with this example. Assuming that summing integers is tedious, we can split that work to smaller jobs. For example, the sum of integers 1 to 100 equals a sum of subtotals.

sum(1, 100) = sum(1, 19) + sum(20, 39) + sum(40, 59) + sum(60, 79) + sum(80, 100)

One bigger task was split to multiple smaller tasks which can be independently done in any order.

# Multiple threads in Java

Now we can spread those subtasks to separate threads. It can be done in a few ways in Java but this time I will use * ExecutorService*.

A big advantage of using it is a fact that *ExecutorService* is available in JDK API, so you do not need any additional library or a framework.

At the beginning, the executor service has to be instantiated. In this example, I create it as a fixed size pool of five threads.

Then I create a list of tasks by creating objects that implement *Callable* interface. When the list is ready, *executorService* runs all those tasks using the pool of threads - it is done by *invokeAll* method.

ExecutorService executorService = Executors.newFixedThreadPool(5);

List<Callable<Integer>> subTasks = List.of(

() -> sum(1, 19),

() -> sum(20, 39),

() -> sum(40, 59),

() -> sum(60, 79),

() -> sum(80, 100)

);

List<Future<Integer>> results = executorService.invokeAll(subTasks);

*invokeAll* returns a list of results. Each result is wrapped by an object implementing *Future* interface. We will get back to that.

# Wait for all threads to finish

Obviously, we are missing summing up all subtotals to get the total sum of integers 1-100. Theoretically, we should wait on all threads to complete calculations and then add up all results according to the below equation.

sum(1, 100) = sum(1, 19) + sum(20, 39) + sum(40, 59) + sum(60, 79) + sum(80, 100)

But how can we make sure that all threads finished? As we used *invokeAll* method, nothing else is required. Once *invokeAll* finishes, results from all threads are available. The method starts all threads from *subTasks* list and waits until they all finished.

A complete code of a junit test which spreads calculation between 5 threads, waits for the result and aggregates them to the total is presented below.

@Test

void shouldExecuteInParallel() throws InterruptedException, ExecutionException {

ExecutorService executorService = Executors.newFixedThreadPool(5);

List<Callable<Integer>> subTasks = List.of(

() -> sum(1, 19),

() -> sum(20, 39),

() -> sum(40, 59),

() -> sum(60, 79),

() -> sum(80, 100)

);

List<Future<Integer>> results = executorService.invokeAll(subTasks);

int total = 0;

for (Future<Integer> result : results) {

total += result.get();

}

assertEquals(5050, total);

}

You may notice that each particular result is read using get method because it is not just a number, it is a *Future* object.

As you can see, *ExecutorService* is useful for executing multiple tasks in parallel without diving deep into technicalities.