【问题标题】:How to create a synchronize block using a @PathVariable in a Spring MVC controller?如何在 Spring MVC 控制器中使用 @PathVariable 创建同步块?
【发布时间】:2014-06-18 17:51:58
【问题描述】:

我需要在 Spring MVC 控制器中创建一个同步块,我想在其中使用 @PathVariable 作为我的同步对象。

@RequestMapping(value = "/upload/{providerId}/{contractId}", method = RequestMethod.POST, headers = "content-type!=multipart/form-data")
public void uploadChunked(
        @PathVariable final long providerId,
        @PathVariable final Long contractId ) {

    Attachment attachment = new Attachment();

    // store the attachment
    synchronized( contractId ){
        contractService.addAttachment( providerId, contractId, attachment );
    }
}

我将 contractId 自动装箱到 Long 并将其用于同步对象,但是如果我在其他地方针对自动装箱的 Long 创建另一个同步块,则在自动装箱值上同步可能会成为问题。根据JLS 5.1.7

理想情况下,装箱一个给定的原始值 p,总是会产生一个 相同的参考。在实践中,这可能不可行 现有的实现技术。

因此,此块可能正在等待盒装 Long 上完全不相关的同步块完成,这是不可接受的。

但是,鉴于控制器本质上是一个单例,我如何安全地与 contractId 同步?需要明确的是,只有对具有相同 contractId 的此方法的调用必须同步 - 具有不同 contractIds 的调用可以同时运行。

我一直找不到任何现有的库来提供这种简单的支持。没有创建我自己的 util lib/class(例如:静态并发 hashmap 来存储 contractId 的锁定对象),还有其他更清洁的解决方案吗?

【问题讨论】:

    标签: java multithreading spring synchronization


    【解决方案1】:

    正如您所建议的,您不能依赖原始包装类型来围绕这些值进行同步。一种可能的解决方案是使用您的contractId 作为密钥来维护ConcurrentHashMap,其中putIfAbsent 是一个新的锁定对象。如果该方法返回一个对象,则锁定该对象。如果没有,则锁定您创建的对象。然后您可以从地图中清除该条目。

    这显然不适用于应用程序的许多部署。

    【讨论】:

    • 感谢您的建议;这几乎也是我的想法。但是为了防止内存泄漏,正如您所建议的,我必须在完成使用后从地图中清除该条目。这意味着我必须跟踪它作为锁定对象被请求并返回的次数。哪个本身(跟踪它被借用/归还的次数)必须在一个同步块中。所以基本上,我自己管理信号量。令我惊讶的是,还没有一个图书馆已经包含了您的所有这些工作。但我在 Guava 或其他中找不到任何东西。
    【解决方案2】:

    有一个名为 XSync 的工具 - 一个线程安全的互斥体工厂,它提供了通过对象的值(而不是对象)进行同步的能力。 您可以将它用于您需要的所有类型的对象。

    https://github.com/antkorwin/xsync

        xSync.execute(contractId, () -> {
               contractService.addAttachment( providerId, contractId, attachment );
        });
    

    【讨论】:

      猜你喜欢
      • 2010-11-26
      • 2019-08-08
      • 1970-01-01
      • 1970-01-01
      • 2013-11-17
      • 2012-08-17
      • 2011-12-21
      • 2015-05-07
      相关资源
      最近更新 更多