Are Spring objects thread safe?

Are Spring objects thread safe? If not, how to make them thread safe?


These are two unrelated questions:

Are Spring Beans Thread Safe?

No.

Spring has different bean scopes (e.g. Prototype, Singleton, etc.) but all these scopes enforce is when the bean is created. For example a "prototype" scoped bean will be created each time this bean is "injected", whereas a "singleton" scoped bean will be created once and shared within the application context. There are other scopes but they just define a time span (e.g. a "scope") of when a new instance will be created.

The above has little, if anything to do with being thread safe, since if several threads have access to a bean (no matter the scope), it would only depend on the design of that bean to be or not to be "thread safe".

The reason I said "little, if anything" is because it might depend on the problem you are trying to solve. For example if you are concerned whether 2 or more HTTP requests may create a problem for the same bean, there is a "request" scope that will create a new instance of a bean for each HTTP request, hence you can "think" of a particular bean as being "safe" in the context of multiple HTTP requests. But it is still not truly thread safe by Spring since if several threads use this bean within the same HTTP request, it goes back to a bean design (your design of a bean backing class).

How to Make/Design a Thread Safe "Object"?

There are several ways, probably too long to list here but here are a few examples:

  • Design your beans immutable: for example have no setters and only use constructor arguments to create a bean. There are other ways, such as Builder pattern, etc..

  • Design your beans stateless: for example a bean that does something can be just a function (or several). This bean in most cases can and should be stateless, which means it does not have any state, it only does things with function arguments you provide each time (on each invocation)

  • Design your beans persistent: which is a special case of "immutable", but has some very nice properties. Usually is used in functional programming, where Spring (at least yet) not as useful as in imperative world, but I have used them with Scala/Spring projects.

  • Design your beans with locks [last resort]: I would recommend against this unless you are working on a lower level library. The reason is we (humans) are not good thinking in terms of locks. Just the way we are raised and nurtured. Everything happens in parallel without us needing to "put that rain on pause, let me get an umbrella". Computers however are all about locks when you are talking "multiple things at the same time", hence there are some of us (exceptional people) who are doing their fair share and implementing libraries based on these locks. Most of other humans can just use these libraries and worry not about concurrency.


Spring does not guarantee thread safety. But it provides guidelines on the matter. If your beans have state do not use singleton bean scope.

I created a demo to show the mutability of spring beans with Singleton and Prototype scope

I focused on stateful beans, then used Singleton and Prototype scopes to show how the beans mutate their state.

The class Job is extended by JobPrototype and JobSingleton beans which are loaded based on the active profile set. Tp set profile, set the property spring.profiles.active to either proto (for prototype scope) or singleton (for Singleton scope)

The active job beans are Autowired inside Runner and Runner1 beans which have Scheduled methods to mutate state of the Autowired bean periodically

public class Job {

    protected int count = 0;

    void counter() {
        this.count++;
    }

    public int getCount() {
        return count;
    }
}



@Component
@Profile("proto")
@Scope("prototype")
public class JobPrototype extends Job {
}

@Component
@Profile("singleton")
public class JobSingleton extends Job {

}

@Component
public class Runner {

    private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private Job job;

    @Scheduled(fixedDelay = 1500)
    void count() {
        this.job.counter();
        Log.info("### Runner: count: " + this.job.getCount());
    }
}

@Component
public class Runner1 {

    private Logger Log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private Job job;

    @Scheduled(fixedDelay = 1000)
    void count() {
        this.job.counter();
        Log.info("### RunnerOne: count: " + this.job.getCount());
    }

}

The results are

  1. Singleton Singleton Scope

  2. Prototype Prototype Scope

Full code for this demo beans_mutability