Understanding Callable and Spring DeferredResult

1 Introduction

Asynchronous support introduced in Servlet 3.0 offers the possibility to process an HTTP request in another thread. This is specially interesting when you have a long running task, since while another thread processes this request, the container thread is freed and can continue serving other requests.

This topic has been explained many times, but there seems to be a little bit of confusion regarding those classes provided by the Spring framework which take advantage of this functionality. I am talking about returning Callable and Spring DeferredResult from a @Controller.

In this post I will implement both examples in order to show its differences.

All the examples shown here consist on implementing a controller which will execute a long running task, and then return the result to the client. The long running task is processed by the TaskService:

public class TaskServiceImpl implements TaskService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    public String execute() {
        try {
            logger.info("Slow task executed");
            return "Task finished";
        } catch (InterruptedException e) {
            throw new RuntimeException();


The web application is built with Spring Boot. We will be executing the following class to run our examples:

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


The source code with all these examples can be found at the Github Spring-Rest repository.

2 Starting with a blocking controller

In this example, a request arrives to the controller. The servlet thread won’t be released until the long running method is executed and we exit the @RequestMapping annotated method.

public class BlockingController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final TaskService taskService;
    public BlockingController(TaskService taskService) {
        this.taskService = taskService;
    @RequestMapping(value = "/block", method = RequestMethod.GET, produces = "text/html")
    public String executeSlowTask() {
        logger.info("Request received");
        String result = taskService.execute();
        logger.info("Servlet thread released");
        return result;


If we run this example at http://localhost:8080/block, looking at the logs, we can see that the servlet request is not released until the long running task has been processed (5 seconds later):

2015-07-12 12:41:11.849  [nio-8080-exec-6] x.s.web.controller.BlockingController    : Request received
2015-07-12 12:41:16.851  [nio-8080-exec-6] x.spring.web.service.TaskServiceImpl     : Slow task executed
2015-07-12 12:41:16.851  [nio-8080-exec-6] x.s.web.controller.BlockingController    : Servlet thread released

3 Returning Callable

In this example, instead of returning directly the result, we will return a Callable:

public class AsyncCallableController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final TaskService taskService;
    public AsyncCallableController(TaskService taskService) {
        this.taskService = taskService;
    @RequestMapping(value = "/callable", method = RequestMethod.GET, produces = "text/html")
    public Callable<String> executeSlowTask() {
        logger.info("Request received");
        Callable<String> callable = taskService::execute;
        logger.info("Servlet thread released");
        return callable;


Returning Callable implies that Spring MVC will invoke the task defined in the Callable in a different thread. Spring will manage this thread by using a TaskExecutor. Before waiting for the long task to finish, the servlet thread will be released.

Let’s take a look at the logs:

2015-07-12 13:07:07.012  [nio-8080-exec-5] x.s.w.c.AsyncCallableController          : Request received
2015-07-12 13:07:07.013  [nio-8080-exec-5] x.s.w.c.AsyncCallableController          : Servlet thread released
2015-07-12 13:07:12.014  [      MvcAsync2] x.spring.web.service.TaskServiceImpl     : Slow task executed

You can see that we have returned from the servlet before the long running task has finished executing. This doesn’t mean the client has received a response. The communication with the client is still open waiting for the result, but the thread that received the request has been released and can serve another client’s request.

4 Returning DeferredResult

First, we need to create a DeferredResult object. This object will be returned by the controller. What we will accomplish is the same with Callable, to release the servlet thread while we process the long running task in another thread.

public class AsyncDeferredController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final TaskService taskService;
    public AsyncDeferredController(TaskService taskService) {
        this.taskService = taskService;
    @RequestMapping(value = "/deferred", method = RequestMethod.GET, produces = "text/html")
    public DeferredResult<String> executeSlowTask() {
        logger.info("Request received");
        DeferredResult<String> deferredResult = new DeferredResult<>();
            .whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
        logger.info("Servlet thread released");
        return deferredResult;


So, what’s the difference from Callable? The difference is this time the thread is managed by us. It is our responsibility to set the result of the DeferredResult in a different thread.

What we have done in this example, is to create an asynchronous task with CompletableFuture. This will create a new thread where our long running task will be executed. Is in this thread where we will set the result.

From which pool are we retrieving this new thread? By default, the supplyAsync method in CompletableFuture will run the task in the ForkJoin pool. If you want to use a different thread pool, you can pass an executor to the supplyAsync method:

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)


If we run this example, we will get the same result as with Callable:

2015-07-12 13:28:08.433  [io-8080-exec-10] x.s.w.c.AsyncDeferredController          : Request received
2015-07-12 13:28:08.475  [io-8080-exec-10] x.s.w.c.AsyncDeferredController          : Servlet thread released
2015-07-12 13:28:13.469  [onPool-worker-1] x.spring.web.service.TaskServiceImpl     : Slow task executed

5 Conclusion

At a high level view, Callable and DeferredResult do the same exact thing, which is releasing the container thread and processing the long running task asynchronously in another thread. The difference is in who manages the thread executing the task.

Finally, if you want to learn more about threading and concurrency, please check my Java Concurrency tutorial

I’m publishing my new posts on Google plus and Twitter. Follow me if you want to be updated with new content.


Share it:

14 thoughts on “Understanding Callable and Spring DeferredResult

  1. Im using Callable, but my controller is confusing the responses on different calls. Do you have an idea what Im doing wrong? My classes used on Callable are prototype and a new instance is created when the thread is created.

  2. Very succinct and neat explanation! I have to do something like this by invoking between 500-1000 REST API service calls to a 3rd party service, get back results from all those calls, mash up the data and send back a response from my controller. Should I use a similar approach or is there a better strategy for something like that?

  3. What should I use if I want the controller to kick off a long running process in a different thread and while that is executing return a temporary result (like this process is running, and the result can be found here at some point in the future) ?

  4. Excellent article. Its possible to use Futures without a DeferredResult, something I found in another article by http://carlmartensen.com/completablefuture-deferredresult-async

    The method would be
    @RequestMapping(value = “/future”, method = RequestMethod.GET, produces = “text/html”)
    public Future executeFutureTask() {
    logger.info(“Request received”);
    CompletableFuture ftr = CompletableFuture.supplyAsync(taskService::execute);
    return ftr;

    1. Thanks!

      Regarding returning Future, I think it won’t work. The result is handled by a list of Spring’s return value handlers. The main async results supported are Callable, DeferredResult and ListenableFuture. You can check DeferredResultMethodReturnValueHandler as an example.

      If you return Future, Spring will try to write the result to the response, resulting in a 406 Not Acceptable error (although the async task will be executed in the background)

Leave a Reply

Your email address will not be published. Required fields are marked *