Spring Async execution


Introduction

Spring offers async behaviour for method calls to achieve unblocking nature. In normal java, we can achieve async method calls by creating a separate thread and call that method via thread runnable.

public static void main(String[] args) {
	TestService testService = new TestService();
	new Thread(() -> testService.test()).start(); //Calling Asynchronously
	testService.test();//Calling synchronously
	new Thread(testService::test, "my-thread").start();//Calling Asynchronously
}

But if you want to make a method call asynchronously without creating thread every time, we need to use spring async functionality.

Enable Async behaviour using spring annotation

  1. Add '@EnableAsync' annotation to spring boot application.
  2. Add '@Async' to any spring bean method. (Other than spring bean it won't work)
  3. Call that method, it won't block the current thread.

SpringBoot Main app - Add '@EnableAsync' on top of the class

package com.oc.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@SpringBootApplication
@EnableAsync
public class RabitMqApplication {
    
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(RabitMqApplication.class, args);
        TestService testService = context.getBean(TestService.class);
        System.out.println("Started Main Thread");
        testService.test();
        testService.test();
        testService.test();
        testService.test();
        System.out.println("Ended Main Thread");
    }
	
}

Test Service - Add '@Asyn' on top of method

package com.oc.app;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class TestService {

    @Async
    public void test() {
        System.out.println("Entered test() By Thread - " + Thread.currentThread().getName());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Ended test()  By Thread - " + Thread.currentThread().getName());
    }
}


Output :

Started Main Thread
Ended Main Thread
Entered test()  By Thread - task-1
Entered test()  By Thread - task-3
Entered test()  By Thread - task-4
Entered test()  By Thread - task-2
Ended test()  By Thread - task-3
Ended test()  By Thread - task-2
Ended test()  By Thread - task-1
Ended test()  By Thread - task-4
  • Note: Above response will take just 5+ secs because of asynchronous execution.

Without @Async annotation

Just comment out @Async on test() for comparing blocking and non-blocking outputs

Output:

Started Main Thread
Entered test()  By Thread - main
Ended test()  By Thread - main
Entered test()  By Thread - main
Ended test()  By Thread - main
Entered test()  By Thread - main
Ended test()  By Thread - main
Entered test()  By Thread - main
Ended test()  By Thread - main
Ended Main Thread
  • Note: Above response will take just 20+ secs because of synchronous execution.