Java 如何防止web服务API中的并发?

Java 如何防止web服务API中的并发?,java,web-services,api,rest,concurrency,Java,Web Services,Api,Rest,Concurrency,我们有三个web服务(/a,/b,/c),其中每个服务映射到一个单独Java类(ClassA,ClassB,ClassC)中的方法(go()) 只能同时运行一个服务(即:/b无法在运行/a时运行)。但是,由于这是一个RESTAPI,因此没有任何东西可以阻止客户端请求并发运行服务 服务器上执行服务不并发运行的最佳和最简单的方法是什么 更新:这是一个内部应用程序,我们不会有太大的负载,只会有一个应用程序服务器 更新:这是一个主观问题,因为您可以对影响最终答案的一般应用程序设计提出不同的论点。我接受

我们有三个web服务(
/a
/b
/c
),其中每个服务映射到一个单独Java类(
ClassA
ClassB
ClassC
)中的方法(
go()

只能同时运行一个服务(即:
/b
无法在运行
/a
时运行)。但是,由于这是一个RESTAPI,因此没有任何东西可以阻止客户端请求并发运行服务

服务器上执行服务不并发运行的最佳和最简单的方法是什么


更新:这是一个内部应用程序,我们不会有太大的负载,只会有一个应用程序服务器


更新:这是一个主观问题,因为您可以对影响最终答案的一般应用程序设计提出不同的论点。我接受了overthink的答案,因为我发现这是最有趣和最有帮助的。

首先,在不了解体系结构的情况下,如果必须对Web服务层实施并发限制,您可能会遇到问题。虽然您可以使用传统的锁等来序列化这两个服务的请求,但当您添加第二个web层来扩展您的解决方案时会发生什么?如果这些锁是web层的本地锁,那么它们几乎毫无用处


我猜在Web服务下面可能有一个类似的层,您需要在这里强制执行这些限制。如果客户机B在客户机A发出冲突请求后进入,则后端在发现状态已更改时应拒绝该请求,然后您应向第二个客户机返回409。最后,竞争条件仍然是可能的,但您必须让最低的公共层保护您免受冲突请求的影响。

您可以使用某种信号量来保持跨串行服务的访问。

假设仅强制web服务器只有一个侦听线程来服务请求是不正确的。。。我想我只需要使用一个静态锁(为了清楚起见,也许你可以在任何共享对象上同步,真的):


你的设计有缺陷。服务应该是幂等的。如果您拥有的类不支持这一点,请重新设计它们,直到它们支持为止。听起来这三种方法都应该是服务的基础,而不是类的基础。

为什么不使用超媒体来限制访问

比如说

POST /A
初始化第一个进程。完成后,结果应提供一个链接,以启动第二个过程

<ResultsOfProcessA>
  <Status>Complete</Status>
  <ProcessB href="/B"/>
</ResultsOfProcessA>
POST /B
然后重复C部分

可以说,行为不好的客户机可能会缓存到步骤B的链接,并试图在将来的某个请求中重新使用该链接以绕过该序列。但是,在执行步骤A时分配某种令牌并要求将令牌传递到步骤B和C以防止客户端手动构建URL并不太困难

进一步阅读您的评论,您可能会遇到这样一种情况:a可以在B之前或之后运行。在这种情况下,我建议创建一个表示整个进程集(a、B和C)状态的资源D。当客户机检索到数据时,会显示允许其遵循的URI。一旦客户机启动了a进程,则D资源应在处理期间删除B链接。当B在A之前启动时,应发生相反的情况

这种技术的另一个优点是,如果A或B已经运行了一天,那么状态可以显示在D中,这是显而易见的。一旦A和B已经运行,那么D可以包含C的链接


超媒体不是100%万无一失的解决方案,因为您可能有两个客户机具有相同的D副本,并且两个客户机都可能认为进程a尚未运行,并且都可能尝试同时运行它。这可以通过在D上有某种“上次修改的”时间戳来解决,并且您可以在D的状态发生变化时更新该时间戳。这可能会导致以后的请求被拒绝。根据您对场景的描述,这似乎更像是一个边缘案例,超媒体将捕获大多数并行运行进程的尝试。

@overthink:当他需要更多服务层时会发生什么?如果在这些层上实现锁,此解决方案将无法扩展。@overthink:那么您是说您也可以使用
synchronized(sharedObject){…}
块而不是
Global.webLock.lock()/unlock()
语句?@Marcus:是的,您可以使用synchronized而不是lock/unlock。e、 在我上面的例子中,你可以把
webLock
变成一个简单的
对象
,然后使用
synchronized(webLock){…}
。@jkp:我不是在试图给出设计建议;只是回答被问到的问题。如果涉及到多个web服务器,这是不可行的,你是对的。@Marcus:这很可能是一个内部应用程序,但是在这个阶段设计一些具有内置限制的东西是个坏主意。你可能认为它永远不需要扩展,但你能确定吗?以后不要再头痛了,坚持一些最佳实践!我能看到阻止类A、B和C中的go()方法并发运行的唯一原因是它们共享了一些东西。如果是类数据或数据库数据,您应该尝试重新设计,使它们不共享任何内容。这将允许它们同时运行,而不必担心干扰。如果这是不可能的,那么您应该有一个按正确顺序调用它们的服务,以确保它们不会被无序调用。不管是哪种情况,我认为你的设计是有缺陷的,治疗效果会比疾病更糟。在设计中有一个很大的问题,信号量、锁等都不是解决这个问题的方法。。整个过程涉及到财务计算<代码>
POST /B