Is Spring controller/service/singleton thread-safe?
It’s a commonly asked question by Spring newcomers and probably a must-have warm-up question on job interviews. As usual in programming, the answer is: it depends. The main factor which determines thread safety of a component is its scope.
Let’s get down to it and see what Spring’s scopes have to offer in multithreaded programming.
Which Spring scope is thread-safe?
In order to answer that question, you first need to understand when Spring creates a new thread.
In a standard servlet-based Spring web application, every new HTTP request generates a new thread. If the container creates a new bean instance just for that particular request, we can say this bean is thread-safe.
Let’s examine what scopes we have in Spring and focus on when the container creates them.
Is Spring singleton thread safe?
The short answer is: no, it isn’t.
And you probably already know why.
It’s because of the long life cycle of singleton beans. Those beans may be reused over and over again in many HTTP requests coming from different users.
If you don’t use @Lazy, the framework creates a singleton bean at the application startup and makes sure that the same instance is autowired and reused in all other dependent beans. As long the container lives, the singleton beans live as well.
But the framework doesn’t control how the singleton is used. If two different threads execute a method of the singleton at the same time, you’re not guaranteed that both calls will be synchronized and run in the sequence.
In other words, it’s your responsibility to ensure your code runs safely in the multithreaded environment. Spring won’t do that for you.
Request scope to the rescue
If you want to make sure your bean is thread-safe, you should go for the @RequestScope. As the name suggests, Spring binds such bean to a particular web request. Request beans aren’t shared between multiple threads, hence you don’t have to care about concurrency.
But hang on a minute.
If request scope beans are so great when it comes to concurrency, maybe we should use the scope for all application beans? Before you set the request scope to all your components, ask yourself the following question.
Do you really need all your beans to be thread-safe?
Usually, you don’t.
Creating a new instance of a bean instead of reusing the existing one is always slower. Stick to singletons unless you have a real use case for request scope beans.
Problematic session scope
Spring associates session beans with a particular user. When a new user visits your application, a new session bean instance is created and reused for all requests from that user.
As you know, some user’s requests may be concurrent. Because of that fact, session beans aren’t thread-safe. Their life cycle is longer than request scope beans. Multiple requests may call the same session bean concurrently.
Tricky thread safety with prototype beans
I left the prototype scope as the last one to discuss because we can’t clearly say it’s always thread-safe or not. Prototype’s thread safety depends on the scope of the bean which contains the prototype.
Spring creates a prototype bean on demand whenever another bean requires its instance.
Imagine you have two beans in your application. One is the singleton and the second is the request scoped component. Both depend on a third bean which is the prototype.
Let’s consider the singleton bean first. Because the singleton isn’t thread-safe, calls to its prototype methods may also run concurrently. When several threads share the singleton, the single instance of the prototype that Spring injects to that singleton will also be shared.
It works the same for all other scopes which make a bean reusable in several web requests.
What about the request scope bean? Spring creates a new instance of such component for each web request. Each request is bound to a separate thread. Therefore, each instance of the request bean gets its own instance of the prototype bean. In that case, you can consider the prototype as thread-safe.
So are Spring web controllers thread-safe or not?
The answer again is: it depends.
It depends on the scope of such a controller.
If you define a controller as the default singleton bean, it won’t be thread-safe. Changing the default scope to the session won’t make the controller safe either. However, the request scope will make the controller bean safe to work for concurrent web requests.
What about controllers with the prototype scope? You already know its thread safety depends on the scope of the bean which contains the prototype as a dependency. But we never inject controllers to other beans, right? They’re entry points to our application. So how does Spring behave when you define a controller as the prototype bean?
As you probably suppose, when you define a controller as the prototype, the Spring framework will create a new instance for each web request it serves. Unless you inject them to unsafe scoped beans, you can consider prototype scoped controllers as thread-safe.
How to make any Spring bean thread-safe?
The best thing you can do to tackle access synchronization is to avoid it.
By making your bean classes stateless.
The bean is stateless if execution of its methods doesn’t modify its instance fields. Changing local variables inside a method is totally fine because each call to a method allocates the memory for these variables. Unlike instance fields which are shared between all non-static methods.
The perfect stateless bean has no fields but you won’t see such utility classes very often. Usually, your beans have some fields. But by applying a few simple rules, you can make any bean stateless and thread-safe.
How to make Spring bean stateless?
Start by making all bean fields final to indicate that during the life cycle of the bean fields shouldn’t be reassigned again.
But don’t confuse field modification with reassignment! Making all bean’s fields final doesn’t make it stateless. If values you assigned to final fields of a bean can be changed during the runtime, such bean is still not thread-safe.
The above example presents a stateless bean because you can’t change the value of the String field. The String class is immutable just like Integer, Boolean, and other primitive wrappers. You can also use primitive types safely in this case. But what about more complex objects like standard Lists, Maps, or your custom data classes?
For the common types like collections, you can go for immutable implementations which you can find in the standard Java library. You can easily create immutable collections with factory methods added in Java 9. If you still use an older version, don’t worry. You can also find conversion methods like unmodifiableList() in the Collections class.
If it comes to custom data types, you have to make sure they are immutable on your own. Creating an immutable class in Java goes beyond the scope of this article. If you need a more detailed guide, read how to design immutable classes in the official Java documentation.
Sounds easy enough. But some of your beans may maintain some state. What then?
Thread-safe variable in stateful Spring bean
Stateless bean sounds like the silver bullet. But what if you already have a stateful bean and you must synchronize access on one of its fields?
In that case, you have the classic Java problem with the concurrent modification access to a class field. The Spring framework won’t solve it for you. You need to select one of the possible solutions:
- The synchronized keyword and Locks – This option gives you the most control over access synchronization but also requires a deeper understanding of mechanisms used in the concurrent environment.
- Atomic variables – You can find a small set of thread-safe types in the Java standard library. Types from that package can be safely used as fields in shared stateful beans.
- Concurrent collections – In addition to atomic variables, Java provides us with a few useful collections which we can use without worrying about the concurrent access problem.
But beware: no matter which method you choose, access synchronization always has an impact on the performance. Try to avoid it if you have an alternative option.
Implementing thread-safe method in Spring component
Frankly, I’ve never had such case in any of my commercial projects but I was asked that question on an interview some time ago so you also may hear it.
As we already discussed, Spring itself doesn’t solve the problem of the concurrent access. If the scope of your bean isn’t thread-safe but its method contains some critical code that you always want to run safely, use the synchronized keyword on that method.
At this point, you should know the position of the Spring framework in the multithreaded environment. You learned how the scope of a component affects its safety and what are the options when you have to provide thread safety on your own.
If you like the post, subscribe to my blog so you won’t miss the next article. Also please leave a comment if you have some interesting stories about tackling concurrency problems in Spring applications. I would love to read them.