Threading and Concurrency in Spring Boot applications

The Spring Framework provides abstractions for asynchronous execution of tasks by using the TaskExecutor interface. Executors are the Java SE name for the concept of thread pools. Spring’s TaskExecutor interface is identical to the java.util.concurrent.Executor interface. The TaskExecutor was originally created to give other Spring components an abstraction for thread pooling where needed. Spring includes a number of pre-built implementations of TaskExecutor but it is the DefaultManagedTaskExecutor that is most useful for integration with CICS as it looks up the application server's defaultExecutor - which in CICS Liberty is designed to provide CICS enabled threads.

About this task

To run asynchronous tasks in your Spring Boot application by using CICS enabled threads, there are two options. You can either set an Asynchronous Executor for the whole application, or you can choose to specify an AsyncExecutor on a per method basis. If all the tasks you spawn asynchronously require CICS services, then setting the Asynchronous Executor for the whole application is the simplest approach. Otherwise, you need to specify the Asynchronous Executor to use for each and every method where you require asynchronous capability. Here, we demonstrate the whole application approach.

Procedure

  1. On your main Spring Boot Application class add the @EnableAsync annotation, implement the interface AsyncConfigurer, and override the getAsyncExecutor() and AsyncUncaughtExceptionHandler methods. Ensure you return an instance of the DefaultManagedTaskExecutor in the getAsyncExecutor() method as this obtains new threads from Liberty's defaultExecutor, which in turn is configured to return CICS enabled threads. For more information about the AsyncConfigurer, see the AsyncConfigurer in the Spring Boot documentation. For usage examples, see EnableAsync in the Spring Boot documentation.
    @SpringBootApplication
    @EnableAsync
    public class MyApplication implements AsyncConfigurer 
    {     
    
        public static void main(String[] args) 
        {
            SpringApplication.run(MyApplication.class, args);
        } 
    
        @Override
        @Bean(name = "CICSEnabledTaskExecutor") 
        public Executor getAsyncExecutor() 
        { 
            return new DefaultManagedTaskExecutor();
        }
    
        @Override 
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() 
        {
            return new CustomAsyncExceptionHandler();
        }
    } 
    
    public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler 
    {
        @Override 
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) 
        {
            System.out.println("Exception Cause - " + throwable.getMessage());
            System.out.println("Method name - " + method.getName()); 
            for (Object param : obj) 
            {
                System.out.println("Parameter value - " + param);
            } 
        }
    }
  2. Add the @Async annotation to either: a class in your application if you wish to run all methods on that class asynchronously, or to individual methods that you wish to run asynchronously. i.e.@Async("CICSEnabledTaskExecutor")
  3. Add the concurrent-1.0 feature to server.xml