java - Spring 线程安全 session bean的最佳实践?

标签 java session spring-mvc thread-safety

我想知道使 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/

相关文章:

java - 在 Java 的子类中实现抽象方法

java - 为什么我的第二个 sqlite 表抛出异常?

php - 授权 Facebook 粉丝页面进行状态更新

php - 如何使用 php 将 session 增量值插入数据库表?

eclipse - spring 工具套件 spring mvc 项目 - 创建后的 22 个问题

java - 在 JPanel 之间切换(隐藏/显示)

java - 在 JNA 中定义 HGlobal

spring - 为什么 Spring boot war 文件只能在 localhost 中使用 artifactId 而不能在 AWS Elastic BeanStalk 中使用?

node.js - Node Express - req.cookies 和 req.session.cookie 的区别

没有 Spring Boot 的 Spring Security JWT 示例