Rory
Rory

Reputation: 1825

Spring MVC Singleton thread safety?

I have a singleton Spring bean (default scope). So, one instance will be used by multiple threads. However, I'm a bit confused with regards thread safety, apparently all Spring beans are thread safe if they are stateless, but my bean is not stateless, it has various instance variables which are used by each request/other controllers/classes.

Here is the beginning of my singleton bean:

public class PcrfSimulator {

private final CustomGxSessionIdCacheImpl gxSessionIdCache = new CustomGxSessionIdCacheImpl();
private final PcrfRecord pcrfRec = new PcrfRecord();
private final ResponseConditions responseConditions = new ResponseConditions();

public CustomGxSessionIdCacheImpl getGxSessionIdCache() {
    return gxSessionIdCache;
}

public ArrayList<Rule> getRules() {
    return pcrfRec.getRules();
}

So, the fields above will be accessed by multiple threads - is it enough to mark these fields as volatile, or do I have to mark the methods which access them (there are a lot in not only this class, but other controllers/classes as well) with synchronized and use wait/notify etc?

Many thanks!

Upvotes: 6

Views: 7624

Answers (4)

Ralph
Ralph

Reputation: 120771

volatile does not help. It would only make sure that the value is really updated.

Volatile means (http://www.javamex.com/tutorials/synchronization_volatile.shtml):

  • The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory";
  • Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.

Making the method synchronized will only help if your control flow never exit the (outer) synchronized block between the first write and the last read to the shared variables, and all shared variables are only accessed within synchronized blocks that use the same lock object.

So the general solution is to prevent shared variables in this scenario. One easy way to make the class immutable is to use local variables and method parameters instead of shared instance variables.


You wrote "Spring beans are thread safe if they are stateless, but my bean is not stateless." -- Ok that theme is discussed in the paragraph above.

But in from your code is seams that this is not the problem! The variables marked with final so they are immutable. If the fields of that object behaves in the same way (are not updated or are adequate protected against concurrent modification problems) you do not have mutable shared variables. Sometimes this is called "effective stateless". This means the values are not changed. So this is no problem for concurrency, (because the concurrency problem is about changing values).

In the end: You can use this effective stateless class from the example in different threads without a synchronized block if the fields (PcrfRecord...) are effective stateless. (If the fields PcrfRecord... are not stateless then the class PcrfSimulator can not been called effective stateless) -- But this has noting to to with Spring, it is plain Java.

Btw: if your variable is final you do not need to make them volantile.

Upvotes: 3

pap
pap

Reputation: 27614

As has been established already, your class is not thread-safe. Prototype-scope is one way to go, but if a prototype-scoped bean is autowired into a singleton bean, it will still mean that only one instance of the prototype bean is created, effectively making it singleton as well.

Synchronization is another way to go, but that really only applies if the instance variables are meant to be shared between threads. If, however, the intention is that the instance variables should be unique to each thread, you should look at ThreadLocal instead.

Upvotes: 0

Erhan Bagdemir
Erhan Bagdemir

Reputation: 5327

Your class won't be thread-safe, if you mark it as singleton in context since you initialize the fields with "new" manually which happens once as the bean is created and of which you will have one instance in memory like your singleton and accordingly, your threads share the instance of CustomGxSessionIdCacheImpl, PcrfRecord and so on.

If you can make these instances take under control of spring context, like:

<bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype">

and autowire them in PcrfSimulator like:

@Autowired
private final CustomGxSessionIdCacheImpl gxSessionIdCache

after that, as soon as your code access on gxSessionIdCache, spring creates a new instance for each access and for each thread respectively. Any other methods in Singleton had to be marked with synchronized since these are open for multi-thread acceess. Spring singletons are regular singletons.

I think, it is wrong to say, if you have no state at all, then everything is thread-safe. If you think low-level, the methods have also states, i.e. local variables, and if multiple threads access these, you can get also a headache.

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691655

Spring itself makes sure to properly publish your beans once they have been instantiated, injected, etc. This means that any thread having a reference to your singleton bean will at least see its state as it was at the end of the Spring context creation.

If the state is immutable, you don't have anything to do.

If the state of the singleton is mutable, you will have to properly synchronize the accesses to this mutable state, though.

Upvotes: 3

Related Questions