Multi-threading with SpringBoot framework – Simple example

A thread is a light-weight smallest part of a process that can run concurrently with the other parts(other threads) of the same process. Threads are independent because they all have separate path of execution that’s the reason if an exception occurs in one thread, it doesn’t affect the execution of other threads. All threads of a process share the common memory. The process of executing multiple threads simultaneously is known as multi-threading. No doubt multi-threading is very important feature in java, but at the same time it comes with bit more complexity.

Spring framework comes with annotations for solving this complexity, with @Async it is very easy to implement Async tasks. Lets do it in coupe of easy steps.

Step 1 : Create a new springboot project in https://start.spring.io/

start.spring.io

Once clicking on generate project, the springboot template will be downloaded into your local system.

Step 2 : Now Import the downloaded maven template project into eclipse as below

Springboot starter template

Open the main application class which has default main method.

Step 3 : Its time to write our async tasks, but first we need to tell spring that enable async feature by using @EnableAsync annotation.

package com.demos.demoProject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoProjectApplication {

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

}

Now create a class where we can write our async tasks as below. There is not much functionality except that it’ll wait for 3 sec and prints the thread name which it is currently running.

Here the method someAsyncMethod is plain old java method except the @Async annotation. So the @Async annotation does all the magic, It’ll make any plain java method into a new thread at run time. So whenever the method someAsyncMethod is called a new thread will be created and the code inside the method will run in that thread. So we can call it as many times as required and every time it will run in a separate thread.

package com.demos.demoProject;

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

@Component
public class AsyncTaskDemo {

	@Async
	public void someAsyncMethod() {
		try {
			Thread.sleep(3000);	// Let me sleep for 3 sec
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("My Name " + Thread.currentThread().getName());
	}
}

Lets prove it: To prove this we need a method invoker, So lets write a controller called DemoController. Creating an endpoints gives us control to trigger our Async code as many times as we want from the web browser.

package com.demos.demoProject;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

	@Autowired
	private AsyncTaskDemo asyncDemo;

	@RequestMapping("/hello")
	public Map<String, String> callAsyncMethod() {

		asyncDemo.someAsyncMethod();
		
		return new HashMap<String, String>();  // returns empty braces
	}
}

Note that we just autowired the AsyncTaskDemo into the controller, and whenever the /hello endpoint is called control is going call our async method.

Now lets start the application and see it in action. Once application is started open web browser and hit http://localhost:8080/hello

Trigger async method

Refresh the page couple of times, and as we refresh a new thread name will be printed in console logs, So this mean every time the method is called the Async framework creates a new thread for us.

Though @Async is very easy to implement, it comes with some limitations

  • The method needs to be public so that it can be proxied
  • Self-invocation of the asynchronous method would not work, because it bypasses the proxy and calls the underlying method directly

For. ex If we call someAsyncMethod() from the AsyncTaskDemo class itself (from another local method), method will be called but it’ll not create a thread.

But from what I see is that the features it has to offer has more weight than the limitations. Since calling a method just as we used to is creating a whole new thread without any manual thread creation, and it a life saving feature of for most of the developers. Apart from that this will reduce lots of development/debugging hours.

Hope you enjoyed the article, if you would like to contribute or improve the content please let me know in the comments.