Algobook
- The developer's handbook
mode-switch
back-button
Buy Me A Coffee
Thu Feb 01 2024

Quick guide on how to use a fixed size thread pool using ExecutorService in Java

In modern applications, concurrency is often a desirable feature that allows multiple tasks to run simultaneously and efficiently. However, creating and managing multiple threads can be challenging and costly, especially when the number of tasks is large or unpredictable. To address this problem, Java provides a high-level abstraction called ExecutorService, which manages a pool of threads and executes tasks submitted to it. Using ExecutorService, developers can focus on the logic of their tasks, rather than the details of thread creation, termination, and synchronization. In this article, we will quickly explore how to use ExecutorService to create and execute a fixed sized thread pool.

Example

Let's create a scenario, where we have a service where we will fetch employee information. Let's imagine that we have three different databases that we need to query in order for our service to get the correct information about the employees.

  • Employee info
  • Address info
  • Personal info

For this, we will setup a thread pool with 3 threads allocated and execute our tasks, in parallel.

Create an interface

We will start by creating an interface called ExecutorTask.java which will have a function called execute. The function will take in an object as a parameter, which we will call ResponseData.

public interface ServiceTask { void execute(ResponseData responseData); }

Setup our Data models

Let's create some data models as well. We will have 4 in total. ResponseData, EmployeeData, AddressData and PersonalData with some example attributes. NOTE: I will use Lombok for our getters and setters to slim down the code, but it is no different than regular void setName(String name) or String getName() for example.

ResponseData.java

import lombok.Getter; import lombok.Setter; @Getter @Setter public class ResponseData { AddressData addressData; EmployeeData employeeData; PersonalData personalData; }

PersonalData.java

import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Getter @Setter @AllArgsConstructor public class PersonalData { String ssn; String name; }

EmployeeData.java

import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Getter @Setter @AllArgsConstructor public class EmployeeData { String role; String employeeNumber; }

AddressData.java

import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Getter @Setter @AllArgsConstructor public class AddressData { String city; String county; String zip; }

Implement the our services

Now, we will create our services. We will have three in total, EmployeeService, AddressService and PersonalDataService which will all implement our interface.

EmployeeService.java

public class EmployeeService implements ServiceTask { @Override public void execute(ResponseData responseData) { System.out.println("Fetching employee data..."); responseData.setEmployeeData(new EmployeeData("Software Engineer", "123")); } }

PersonalDataService.java

public class PersonalDataService implements ServiceTask { @Override public void execute(ResponseData responseData) { System.out.println("Fetching personal data..."); responseData.setPersonalData(new PersonalData("20200101-1122", "John Doe")); } }

AddressService.java

public class AddressService implements ServiceTask { @Override public void execute(ResponseData data) { System.out.println("Fetching address info..."); data.setAddressData(new AddressData("Malmo", "Skane", "123 45")); } }

Execute our tasks using ServiceExecutor

Now, we will execute our task. In our Main.java (or whatever you want to call it) - we will create our thread pool and execute our tasks in parallel.

Create List of tasks and our executor service

private static final ExecutorService executorService = Executors.newFixedThreadPool(3); private static final List<ServiceTask> tasks = new ArrayList<>();

We will allocate three threads to our pool and create a List<> of ServiceTask.

Main method

In our main method, we will create our services and add them to the list and execute them.

public static void main(String[] args) { ResponseData responseData = new ResponseData(); AddressService addressService = new AddressService(); EmployeeService employeeService = new EmployeeService(); PersonalDataService personalDataService = new PersonalDataService(); tasks.addAll(List.of(addressService, employeeService, personalDataService)); tasks.forEach(t -> executeTasks(t, responseData)); executorService.shutdown(); }

executeTask() method

Now, we will create the method that will to the execution.

private static void executeTask(ServiceTask task, ResponseData responseData) { executorService.submit(() -> { System.out.println("Thread: " + Thread.currentThread().getName() + " is running."); task.execute(responseData); }); }

Run the program

And now we are ready to run our program. If you try this out yourself, you will notice that the order of the logs will differ for every time you run it. This is beacause of the nature of multi-threading. The threads will run in different order depending on how the JVM and the underlying OS will schedule them accordingly.

Some examples of prints:

1st run:

Thread: pool-1-thread-2 is running. Fetching employee data... Thread: pool-1-thread-1 is running. Thread: pool-1-thread-3 is running. Fetching personal data... Fetching address info..

2nd run:

Thread: pool-1-thread-1 is running. Fetching address info... Thread: pool-1-thread-2 is running. Thread: pool-1-thread-3 is running. Fetching personal data... Fetching employee data...

3rd run:

Thread: pool-1-thread-3 is running. Fetching personal data... Thread: pool-1-thread-2 is running. Fetching employee data... Thread: pool-1-thread-1 is running. Fetching address info...

Summary

In this article we took a first glance at ServiceExecutor in Java, where we setup a fixed thread pool that were doing some basic tasks. I hope you enjoyed this article and that it could help you get started with your journey towards multi-threading in Java using ServiceExecutor interface.

Any questions? Don't hesitate to contact us.

All the best,

signatureThu Feb 01 2024
See all our articles