I'm wondering what is the best practice for making a session bean thread safe.
Let's assume I have this session bean and its service:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
class Cart {
private HashSet<Item> items = new HashSet<Item>();
private int counter = 0;
public HashSet<Item> getItems() {
return items;
}
public int getCounter() {
return counter;
}
}
@Service
class CartService {
@Autowired
private Cart cart;
public void addItem(Item item) throws FullException {
if (cart.getCounter() > 1234) {
throw new FullException();
}
cart.getItems().add(item);
}
}
The code above is not thread safe and will cause issues when multiple threads (of the same session, eg. by asynchronous Ajax-requests) perform a CartService.addItem(Item)
.
I think I'm not the first with this problem, but my researches didn't bring me to a best practice.
The worst thing I could do would synchronize addItem() as CartService is shared by multiple sessions. Synchronizing on cart in CartService.addItem()
seems to me similarly bad, as Cart is a proxied bean. Which I understand as all sessions would still synchronize on the same object.
One acceptable solution seems to be a synchronized block on Cart.getItems()
in CartService.addItem()
:
@Service
class CartService {
@Autowired
private Cart cart;
public void addItem(Item item) {
synchronized(cart.getItems()) {
if (cart.getCounter() > 1234) {
throw new FullException();
}
cart.getItems().add(item);
}
}
}
Is there any best practice? Maybe spring has something to offer for this problem?
After digging a bit through the Spring API I found RequestMappingHandlerAdapter.setSynchronizeOnSession(boolean)
which seems to synchronize every controller on a session mutex. This might be overkill. But it makes at least controllers thread safe on the session without blocking other users, plus I don't have to worry about synchronization in my controller. But this is still not acceptable for a highly responsive Ajax-GUI.
I get the feeling that there is no general answer to this question and it totally depends on the GUI. If I have plain simple HTML pages where sequential requests are expected RequestMappingHandlerAdapter.setSynchronizeOnSession(true)
seems to be perfect, as I don't have to think about synchronization in my Controllers.
If the GUI becomes more fancy with loads of parallel AJAX-requests I have to take care about synchronization by choosing an eligible mutex.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With