我想知道使 session bean 线程安全的最佳实践是什么。
假设我有这个 session bean 及其服务:
@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);
}
}
上面的代码不是线程安全的,当多个线程(同一 session 的,例如通过异步 Ajax 请求)执行 CartService.addItem(Item)
时会导致问题。
我想我不是第一个遇到这个问题的人,但我的研究并没有给我带来最佳实践。
我能做的最糟糕的事情是同步 addItem(),因为 CartService 由多个 session 共享。在 CartService.addItem()
中同步购物车在我看来同样糟糕,因为 Cart 是一个代理 bean。据我所知,所有 session 仍将在同一对象上同步。
一个可接受的解决方案似乎是 CartService.addItem()
中 Cart.getItems()
上的同步块(synchronized block):
@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);
}
}
}
有什么最佳实践吗?也许 spring 可以解决这个问题?
最佳答案
在深入了解 Spring API 之后,我发现 RequestMappingHandlerAdapter.setSynchronizeOnSession(boolean)
似乎可以同步 session 互斥锁上的每个 Controller 。这可能有点矫枉过正。但它至少使 session 中的 Controller 线程安全,而不会阻塞其他用户,而且我不必担心 Controller 中的同步问题。但这对于高度响应的 Ajax-GUI 来说仍然是 Not Acceptable 。
我觉得这个问题没有通用的答案,它完全取决于 GUI。如果我有纯简单的 HTML 页面,其中需要顺序请求,RequestMappingHandlerAdapter.setSynchronizeOnSession(true)
似乎是完美的,因为我不必考虑 Controller 中的同步。
如果 GUI 因大量并行 AJAX 请求而变得更加花哨,我必须通过选择符合条件的互斥锁来注意同步。
关于java - Spring 线程安全 session bean的最佳实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19443046/