Alessio Fiore
Alessio Fiore

Reputation: 467

How to make Spring beans thread-safe

As far as I know, Spring beans are singleton by default.

What I want is make beans thread-safe considering instance attributes. I'll try to show you using a simple example.
Consider the following code:

@Controller
public class MyServlet {

    @Autowired
    private HelloService service;

    @RequestMapping(value="/hello", method = RequestMethod.GET)
    public void sayHello(HttpServletRequest req, HttpServletResponse res) throws IOException {
        service.doStuff();
    }

}


public class HelloService {

    private int i = 1;

    public void doStuff() {
        System.out.println("Started " + i);
        i++;
        System.out.println(Thread.currentThread().getName() + " Done " + i);
    }
}

The output will be something like this:

32911580@qtp-28064776-0 - Started 1
7802158@qtp-28064776-2 - Started 2
32911580@qtp-28064776-0 - Done 3
7802158@qtp-28064776-2 - Done 3

This prove the "i" var is shared between multiple threads.

I've also tryed to define the HelloService bean as prototype, like this

<bean id="helloService" class="my.package.HelloService" scope="prototype" />

but the result is the same.

The only ways I found to solve this are: - move the declaration into doStuff() method, but it's not what I want - make the doStuff() method, but this means have locks

What I would like is have a new instance of HelloService on every call.

Can anyone help me? Thanks in advance.

Update

I found the solution with method injection using lookup-method. http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection

Upvotes: 3

Views: 19430

Answers (3)

Andrey Tkachuk
Andrey Tkachuk

Reputation: 46

I've also tried to define the HelloService bean as prototype, but the result is the same.

You got the same result because your MyServlet is singleton. So you have only one MyServlet instance, hence you have only one HelloService instance. If you make MyServlet as prototype bean as well, you will be get every time new instances for both

Upvotes: 1

theRiley
theRiley

Reputation: 1167

Adding to Thomas' answer, for a service bean, request-scope is the best choice for a stateful & thread-safe component, since only one instance is normally called for in that scope.

If multiple (stateful & thread-safe) beans are needed within a particular application scope, prototype-scope would be the most appropriate choice.

Upvotes: 1

Thomas Krieger
Thomas Krieger

Reputation: 1633

Since you have only one instance of MyServlet you will also have only one instance of HelloService.

One of the following spring scopes help: request A new instance for each HTTP request. session A new instance of the class for each new HttpSession created in a servlet container.

This will change the semantics of your code. If you declare the bean in the scope request your counter will always be 1.

To have one unique counter without locks you could use java.util.concurrent.atomic.AtomicInteger.

On the other side there is nothing bad about locks. The performance impact is neglectible in most except extreme cases.

After you have built your application check it with http://vmlens.com for race conditions.

Upvotes: 3

Related Questions