Monday, May 9, 2022

Spring Thread Pooling Support Using TaskExecutor

In this post we’ll see the Spring framework support for thread pools along with a Spring ThreadPoolTaskExecutor example for configuring a thread pool. Abstraction provided through Spring TaskExecutor interface hides implementation details between Java SE and Java EE environments.

Spring framework’s TaskExecutor interface

Spring framework provides a TaskExecutor interface that abstracts the execution of a Runnable.

Implementations can use all sorts of different execution strategies, such as: synchronous, asynchronous, using a thread pool, and more.

TaskExecutor interface is Equivalent to JDK 1.5's Executor interface. In fact TaskExecutor extends it from Spring 3.0 onward, so that clients may declare a dependency on an Executor and receive any TaskExecutor implementation.

TaskExecutor implementations

As already stated above for different execution strategies there are different implementations of TaskExecutor interface. Though the most commonly used implementation is ThreadPoolTaskExecutor.

  • SimpleAsyncTaskExecutor- This implementation does not reuse any threads. A new thread is started for each invocation. However, it does support a concurrency limit which will block any invocations that are over the limit until a slot has been freed up.
  • SyncTaskExecutor- This implementation doesn’t execute invocations asynchronously. Instead each invocation takes place in the calling thread. It is primarily used in situations where multithreading isn’t necessary such as simple test cases.
  • ConcurrentTaskExecutor- This implementation is an adapter for a java.util.concurrent.Executor object.
  • SimpleThreadPoolTaskExecutor- This implementation is actually a subclass of Quartz’s SimpleThreadPool which listens to Spring’s lifecycle callbacks. This is typically used when you have a thread pool that may need to be shared by both Quartz and non-Quartz components.
  • ThreadPoolTaskExecutor- This implementation is the most commonly used one. It exposes bean properties for configuring a java.util.concurrent.ThreadPoolExecutor and wraps it in a TaskExecutor.
  • WorkManagerTaskExecutor- This implementation uses the CommonJ WorkManager as its backing implementation and is the central convenience class for setting up a CommonJ WorkManager reference in a Spring context.

Thread pooling in Spring using TaskExecutor example

Here is a simple example where a thread pool is configured using a ThreadPoolTaskExecutor, threads from the pool are used to execute Runnable task.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
@Component
public class TaskExecutorDemo {
  @Autowired
  private TaskExecutor taskExecutor;
      
  public void printMessages() {
    for(int i = 0; i < 15; i++) {
      taskExecutor.execute(new MessagePrinterTask("Message" + i));
    }
  }
  
  private class MessagePrinterTask implements Runnable {
    private String message;
    public MessagePrinterTask(String message) {
      this.message = message;
    }
    public void run() {
      System.out.println(message + " Printed by " + Thread.currentThread().getName());
    }
  }
}

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="org.netjs.service" />
  <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="4" />
    <property name="maxPoolSize" value="6" />
    <property name="queueCapacity" value="15" />
  </bean>
</beans>

You can run the example using the following code.

public class App {
  public static void main( String[] args ){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    TaskExecutorDemo td = (TaskExecutorDemo) context.getBean("taskExecutorDemo");
    td.printMessages();
    context.registerShutdownHook();
  }
}

Thread pooling with Spring managed bean example

In the above example Runnable is implemented as a private class with in the Bean. If you want to spawn threads too as Spring managed bean then the same example can be written as below.

Spring managed Runnable instances

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class MessagePrinterTask implements Runnable{
 private String message;
 public MessagePrinterTask(String message) {
  this.message = message;
 }
 public void run() {
  System.out.println(message + " Printed by " + Thread.currentThread().getName());
  try {
   Thread.sleep(500);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Class with TaskExecutor

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
@Component
public class TaskExecutorDemo implements ApplicationContextAware {
  @Autowired
  private TaskExecutor taskExecutor;
  private ApplicationContext applicationContext;
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
    
  public void printMessages() {
    for(int i = 0; i < 15; i++) {        
      taskExecutor.execute(applicationContext.getBean(MessagePrinterTask.class, "Message" + i));
    }
  }
}

Configuration for TaskExecutor is same as used above.

That's all for this topic Spring Thread Pooling Support Using TaskExecutor. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Email Scheduling Example Using Quartz Scheduler
  2. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  3. Wiring Collections in Spring
  4. Circular Dependency in Spring Framework
  5. @Required Annotation in Spring Framework

You may also like-

  1. How to Inject Prototype Scoped Bean into a Singleton Bean in Spring
  2. Spring Profiles With Examples
  3. Spring NamedParameterJdbcTemplate Select Query Example
  4. How to Inject Null And Empty String Values in Spring
  5. Type Casting in Java With Conversion Examples
  6. Nested class and Inner class in Java
  7. Java Stream API Tutorial
  8. Volatile Keyword in Java With Examples