Callable / Runnable Controller methods What's the point?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Spring MVC, returning Callable from a controller is about asynchronous request processing. The controller hands Spring a unit of work, Spring releases the servlet thread, runs the task on an async executor, and resumes request processing when the result is ready.
That is why Callable has a real role in controller methods and Runnable usually does not. Callable produces a value or throws an exception. A controller needs exactly that. Runnable returns nothing, so by itself it is not a useful controller return type.
Why Callable Fits A Controller
A normal controller method returns something Spring knows how to render: a view name, an object, a ResponseEntity, and so on. Callable<V> wraps one of those return values so it can be computed later on a different thread.
Spring can wait for the Callable to finish and then treat its result as the real controller return value.
Why Runnable Usually Is Not Returned
A Runnable can run work asynchronously, but it cannot hand a value back to Spring:
That can be useful inside your own service layer or executor setup, but if a controller returns Runnable, Spring still needs to know what HTTP response to send. Since Runnable has no result, it does not solve the request-response problem.
If you really want fire-and-forget behavior, that is usually an application design question, not a controller return-type trick. The controller still needs to send some response immediately, such as 202 Accepted.
What Problem Async Controllers Solve
The main benefit is thread usage. In a synchronous controller, the servlet container thread stays occupied while the work runs. With Callable, Spring can release that request thread while the background task continues.
That helps when the controller waits on slow I/O, heavy computation, or an external service. It does not automatically make the work faster, but it can improve throughput because request threads are not blocked the entire time.
Modern Alternatives
Callable is not the only async option. Spring MVC also supports DeferredResult, WebAsyncTask, and convenient future-like return types such as CompletionStage and CompletableFuture.
The rule of thumb is:
- use
Callablewhen Spring should run the task for you - use
DeferredResultwhen some other thread or event will complete the response later - use
CompletableFuturewhen the underlying service already works that way
So the point of Callable is not that it is more magical than Runnable. The point is that it fits the HTTP response contract.
Common Pitfalls
- Thinking
Callablemakes CPU-heavy code free instead of merely shifting where it runs. - Returning
Runnableand expecting Spring to infer a response body. - Forgetting that async controller work still needs proper executor configuration.
- Using async return types when the real bottleneck is elsewhere, such as database design or blocking service code.
- Assuming Spring MVC async controllers behave the same way as fully reactive WebFlux handlers.
Summary
- '
Callableis useful in controllers because it can eventually return the real HTTP result.' - '
Runnableusually is not a controller return type because it returns nothing.' - Async controller methods free the servlet request thread while background work runs.
- '
Callablehelps throughput, not necessarily raw execution speed.' - Choose
Callable,DeferredResult, or futures based on who produces the eventual response value.

