Monday 15 April 2024

Creating a Thread Pool and Executing Async Tasks in spring boot application

In Spring, you can create a thread pool using the TaskExecutor interface or its implementations such as ThreadPoolTaskExecutor. Then, you can submit asynchronous tasks to this thread pool to save data to the database asynchronously. Here's how you can do it:

 

1. Define a TaskExecutor Bean: Configure a ThreadPoolTaskExecutor bean in your Spring configuration. This bean will represent your thread pool.

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
	ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
	executor.setCorePoolSize(5); // Set the number of threads in the pool
	executor.setMaxPoolSize(10); // Set the maximum number of threads in the pool
	executor.initialize();
	return executor;
}

 

2. Define an asynchronous task class.

@Component
@Scope("prototype")
public class AsyncDataPublisherTask implements Runnable {
}

 

AsyncDataPublisherTask class is a Spring-managed component with prototype scope, meaning that each time it's requested from the application context, a new instance will be created. It also implements the Runnable interface, making it suitable for asynchronous execution by a thread. This setup is commonly used for defining tasks that need to be executed asynchronously, such as background processing or handling concurrent operations.

 

 

3. Submit Async Tasks: Inject the TaskExecutor bean into your service or component where you want to perform asynchronous operations. Then, submit tasks to the thread pool using the TaskExecutor.execute() or TaskExecutor.submit() methods.

 

@Autowired
private ThreadPoolTaskExecutor taskExecutor;

AsyncDataPublisherTask asyncTask = appContext.getBean(AsyncDataPublisherTask.class);
taskExecutor.execute(asyncTask);

Find the below working application.

 

Step 1: Create new maven project ‘springboot-async-tasks’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sample.app</groupId>
  <artifactId>springboot-async-tasks</artifactId>
  <version>0.0.1-SNAPSHOT</version>
<properties>
		<maven.compiler.source>17</maven.compiler.source>
		<maven.compiler.target>17</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.2</version>
	</parent>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springdoc</groupId>
			<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
			<version>2.0.4</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Step 3: Define AsyncDataPublisherTask.

 

AsyncDataPublisherTask.java

package com.sample.app.tasks;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.sample.app.service.DBService;

@Component
@Scope("prototype")
public class AsyncDataPublisherTask implements Runnable {

	private static final Logger LOG = LoggerFactory.getLogger(AsyncDataPublisherTask.class);

	@Autowired
	private DBService dbService;

	private String msg;

	public void setMsg(String msg) {
		this.msg = msg;
	}


	@Override
	public void run() {
		LOG.info("thread: {}, is publishing the msg {} to database", Thread.currentThread().getName(), msg );
		dbService.save(msg);
		LOG.info("thread: {}, is published the msg {} to database", Thread.currentThread().getName(),  msg);

	}

}

Step 4: Define DBService class.

 

DBService.java

package com.sample.app.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class DBService {
	private static final Logger LOG = LoggerFactory.getLogger(DBService.class);
	
	public void save(String msg) {
		LOG.info("msg {} is saved to database", msg);
	}
	

}

Step 5: Define AppConfig class.

 

AppConfig.java

package com.sample.app.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class AppConfig {
	@Bean
	public ThreadPoolTaskExecutor taskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(5); // Set the number of threads in the pool
		executor.setMaxPoolSize(10); // Set the maximum number of threads in the pool
		executor.initialize();
		return executor;
	}

}

Step 6: Define main application class.

 

App.java

package com.sample.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.sample.app.tasks.AsyncDataPublisherTask;

@EnableAsync
@EnableScheduling
@SpringBootApplication
public class App {
	private static final Logger lOG = LoggerFactory.getLogger(App.class);

	private static int count = 0;

	@Autowired
	private ThreadPoolTaskExecutor taskExecutor;

	@Autowired
	private ApplicationContext appContext;

	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}

	@Scheduled(fixedDelay = 30 * 1000)
	public void saveMsgs() {
		lOG.info("****Publishing 20 messages to the database in async way****");
		for (int i = 0; i < 20; i++) {
			count++;
			AsyncDataPublisherTask asyncTask = appContext.getBean(AsyncDataPublisherTask.class);
			lOG.info("asyncTask {} is created", asyncTask);
			asyncTask.setMsg("msg->" + count);
			taskExecutor.execute(asyncTask);
		}

	}
}

Total project structure looks like below.




Build the project.

Go the location where pom.xml is located and execute below command.

mvn package

 

Upon successful execution of the command, you can see the jar springboot-async-tasks-0.0.1-SNAPSHOT.jar in target folder. Execute below command to run the application.

 

java -jar ./target/springboot-async-tasks-0.0.1-SNAPSHOT.jar

 

You can see below messages in the console.

2024-04-16T11:19:44.829+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : ****Publishing 20 messages to the database in async way****
2024-04-16T11:19:44.830+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : asyncTask com.sample.app.tasks.AsyncDataPublisherTask@207ab7b5 is created
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : asyncTask com.sample.app.tasks.AsyncDataPublisherTask@2a077820 is created
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-1] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-1, is publishing the msg msg->1 to database
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-1] com.sample.app.service.DBService         : msg msg->1 is saved to database
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-1] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-1, is published the msg msg->1 to database
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-2] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-2, is publishing the msg msg->2 to database
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : asyncTask com.sample.app.tasks.AsyncDataPublisherTask@212a4c2a is created
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-2] com.sample.app.service.DBService         : msg msg->2 is saved to database
2024-04-16T11:19:44.832+05:30  INFO 75627 --- [ taskExecutor-2] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-2, is published the msg msg->2 to database
2024-04-16T11:19:44.833+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : asyncTask com.sample.app.tasks.AsyncDataPublisherTask@19248161 is created
2024-04-16T11:19:44.833+05:30  INFO 75627 --- [ taskExecutor-3] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-3, is publishing the msg msg->3 to database
2024-04-16T11:19:44.833+05:30  INFO 75627 --- [ taskExecutor-3] com.sample.app.service.DBService         : msg msg->3 is saved to database
2024-04-16T11:19:44.833+05:30  INFO 75627 --- [ taskExecutor-3] c.s.app.tasks.AsyncDataPublisherTask     : thread: taskExecutor-3, is published the msg msg->3 to database
2024-04-16T11:19:44.833+05:30  INFO 75627 --- [   scheduling-1] com.sample.app.App                       : asyncTask com.sample.app.tasks.AsyncDataPublisherTask@26ea04fa is created

You can download the application from this link.



 

Previous                                                 Next                                                 Home

No comments:

Post a Comment