【问题标题】:Preventing Java web service from concurrent modification of record防止 Java Web 服务同时修改记录
【发布时间】:2014-09-06 02:30:05
【问题描述】:

我在 Tomcat 中运行 Java Web 服务。

该服务由多个 Rails 应用程序使用,这些应用程序应该协调并发修改,但做得不是很好。

只有一种感兴趣的服务方法会尝试 PUT 用户记录,但它会进行大量处理并且可能需要一段时间。很有可能不止一个 Rails 应用程序会尝试将更改推送给同一用户,而之前的调用仍在处理中。

我对 Tomcat 的每个请求一个线程的理解是,我实际上是在处理多线程问题,但我不想在服务对象上同步,而是想以某种方式在瞬态用户 ID 上同步。

我想到了使用 Set 来存储当前处理的用户 ID,然后在集合的对象上进行同步。能够将用户 ID 添加到集合中的第一个可以进行处理,而发现集合中已有用户 ID 的则返回,例如 409 冲突错误。

Set<String> activeUserIds = new HashSet<String>();

// annotations, mappings, etc.
public ResponseEntity<String> putUser(User user) {

    boolean canProcess;
    synchoronize(activeUserIds) {
        canProcess = activeUserIds.add(user.getId()) {
    }

    if (!canProcess) {
        return new ResponseEntity<String>("user already being modified", Status.CONFLICT);
    }

    // perform service activity

    synchoronize(activeUserIds) {
        activeUserIds.remove(user.getId()) {
    }

}

这听起来可行吗?我还没有发现 Tomcat 或 Spring MVC 中内置的任何东西可以自动处理这种行为,但是是否已经有我不知道的内置解决方案?

【问题讨论】:

  • 任何使用 Java 并发操作的解决方案(仅)只能在您的应用程序未跨多台机器/JVM 集群时工作。您使用什么后端存储来存储用户记录?如果您使用的是 SQL 数据库,则可以在请求处理代码的开头锁定该行。

标签: java multithreading spring tomcat


【解决方案1】:

我认为你提出的解决方案应该可以工作,只要你有一个 webapp 实例正在运行(正如 Erwin 在 cmets 中指出的那样)。我不知道有任何内置解决方案可以做到这一点。

为了使代码更易于阅读,您还可以使用同步集并去掉两个synchronized 语句:

Set<String> activeUserIds = Collections.synchronizedSet(new HashSet<String>());

【讨论】:

    猜你喜欢
    • 2019-03-06
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 2017-08-08
    • 2011-03-28
    • 2021-09-21
    相关资源
    最近更新 更多