views:

385

answers:

3

Does singleton/session scopes of Spring beans require that access to all its fields must be synchronized? Say through "synchronized" keyword or using some classes from package "java.util.concurrent".

As example, is this code not thread safe? (copy/pased from here):

@Component
@SessionScoped
public class ShoppingCart {
    private List<Product> items = new ArrayList<Product>();

    public List<Product> getAllItems() {
        return items;
    }

    public void addItem(Product item) {
        items.add(item);
    }
}
A: 

Only the user for that session can access this class, but ArrayList is not thread-safe, as seen in this discussion: http://forums.sun.com/thread.jspa?threadID=5355402

You need to ensure that your class is fully thread-safe as SessionScoped will just ensure that it is only used by each session, so one session can't access it.

You may want to look at the comments in this discussion for more info: http://wheelersoftware.com/articles/spring-session-scoped-beans.html

James Black
+9  A: 

When you use singleton scope from the Spring container, you indicate that all threads that retrieve the bean from the container will use the same instance. So in this case, where the state list of item is shared and modifiable between threads, you would have to synchronize access to the list to protect your application against a ConcurrentModificationException.

However, the usual practice with Spring is to build your application with stateless objects, which don't have state that will be changing throughout the life of the application.

In the case of session scope, you might be less likely to see a concurrency problem since the bean will only be accessible by the currently logged in user. However, it's possible (at least on the web) to have multiple requests coming in on the same session, in which case you would need to take the same precautions as if the bean were a singleton.

Again the best way to protect yourself is to try to keep your bean as stateless as possible. If you have a bean that requires state, you should consider using the prototype scope, which retrieves a new instance of the bean from the container each time.

Jason Gritman
A: 

Basically for every user that initiates a session a new ShoppingCart will be created and scoped to that session per that user.

Your class is thread-safe. The initialization

private List<Product> items = new ArrayList<Product>();

is a thread-safe initialization and

addItem(Product item) is an atomic operation and is also therefore thread-safe.

non sequitor
If someone calls getItems() and starts iterating over it, while at the same time another thread does an addItem(), you'll barf up a ConcurrentModificationException. See http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html for notes on what needs to be synchronized for thread safety with ArrayList.
Jason Gritman
The class is not thread-safe because 'items' collection is not safely published; items.add() doesn't provide any guarantee that its effect is visible to the thread over than current and it is not atomic.
denis.zhdanov
Hmmm I was under the impression that the fact that the class is also `SessionScoped` and can only be acted on by a single actor within the Spring container would ensure the thread safety of the class?
non sequitor