Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With default bean scope as singleton, isn't it going to be bad when concurrent calls occur?

I have declared a Spring bean, which polls my email server every so and so seconds. If there is mail, it fetches it, and tries to extract any attached files in it. These files are then submitted to an Uploader which stores them safely. The uploader is also declared as a Spring bean. A third bean associates the email's sender with the file's filename and stores that in a DB.

It turned out that when a few people tried to send emails at the same time, a bunch of messy stuff happened. Records in the DB got wrong filenames. Some did not get filenames at all, etc.

I attributed the problem to the fact that beans are scoped to singleton by default. This means that a bunch of threads are probably messing up with one and the same instance at the same time. The question is how to solve this.

If I synchronize all the sensitive methods, then all threads will stack up and wait for each other, which is kind of against the whole idea of multithreading.

On the other hand, scoping the beans to "request" is going to create new instances of each of them, which is not really good either, if we speak about memory consumption, and thread scheduling

I am confused. What should I do?

like image 608
user802232 Avatar asked Sep 29 '11 12:09

user802232


5 Answers

Singleton-scoped beans should not hold any state - that solves the problem usually. If you only pass data as method parameters, and don't assign it to fields, you will be safe.

like image 98
Bozho Avatar answered Oct 16 '22 08:10

Bozho


I agree with both @Bozho and @stivio answers.

The preferred options are to either pass store no state in a singleton scoped beans, and pass in a context object to the methods, or to use a prototype / request scoped beans that get created for every processing cycle. Synchronization can be usually avoided, by choosing one of these approaches, and you gain much more performance, while avoiding deadlocks. Just make sure you're not modifying any shared state, like static members.

There are pros and cons for each approach:

  1. Singlton beans are act as a service-like class, which some may say are not a good Object-Oriented design.
  2. Passing context to methods in a long chain of methods may make your code messy, if you're not careful.
  3. Prototype beans may hold a lot of memory for longer than you intended, and may cause memory exhaustion. You need to be careful with the life cycle of these beans.
  4. Prototype beans may make your design neater. Make sure you're not reusing beans by multiple threads though.

I tend to go with the service approach in most simple cases. You can also let these singleton beans create a processing object that can hold it's state for the computation. This is a solution that may serve you best for the more complexed scenarios.

Edit: There are cases when you have a singleton bean depending on prototype scoped bean, and you want a new instance of the prototype bean for each method invocation. Spring supplies several solutions for that:

The first is using Method Injection, as described in the Spring reference documentation. I don't really like this approach, as it forces your class to be abstract.

The second is to use a ServiceLocatorFactoryBean, or your own factory class (which needs to be injected with the dependencies, and invoke a constructor). This approach works really well in most cases, and does not couple you to Spring.

There are cases when you also want the prototype beans to have runtime dependencies. A good friend of mine wrote a good post about this here: http://techo-ecco.com/blog/spring-prototype-scoped-beans-and-dependency-injection/.

like image 34
Eran Harel Avatar answered Oct 16 '22 08:10

Eran Harel


Otherwise just declare your beans as request, don't worry about the memory consumption, the garbage collection will clear it up, as long there is enough memory it won't be a performance problem too.

like image 27
stivlo Avatar answered Oct 16 '22 10:10

stivlo


Speaking abstractly: if you'e using Spring Integration, then you should build your code in terms of the messages themselves. Eg, all important state should be propagated with the messages. This makes it trivial to scale out by adding more spring Integration instances to handle the load. The only state (really) in Spring Integration is for components like the aggregator, which waits and collects messages that have a correllation. In this case, you can delegate to a backing store like MongoDB to handle the storage of these messages, and that is of course thread safe.

More generally, this is an example of a staged event driven architecture - components must statelessly (N(1) no matter how many messages) handle messages and then forward them on a channel for consumption by another component that does not know about the previous component from which the message came.

If you are encountering thread-safety issues using Spring Integration, you might be doing something a bit differently than intended and it might be worth revisiting your approach...

like image 2
Josh Long Avatar answered Oct 16 '22 08:10

Josh Long


Singletons should be stateful and thread-safe.

If a singleton is stateless, it's a degenerate case of being stateful, and thread-safe is trivially true. But then what's the point of being singleton? Just create a new one everytime someone requests.

If an instance is stateful and not thread-safe, then it must not be singleton; each thread should exclusively have a different instance.

like image 1
irreputable Avatar answered Oct 16 '22 08:10

irreputable