Java 并发FindModify查询成功更新同一文档

Java 并发FindModify查询成功更新同一文档,java,mongodb,Java,Mongodb,我有一个用Java编写的任务工作者,使用MongoDB 3.4副本集,该副本集运行许多线程,每个线程基本上都这样做 运行任务 通过在MongoDB中更新该任务的文档来表示该任务已完成 运行查询以查看此任务集中的所有任务是否都已完成 如果是,请继续下一阶段的处理 否则,什么也不做 正如你可能看到的,这里有一个竞赛条件;多个任务几乎可以同时完成,并且认为它们是最后一个要完成的任务。我想使用MongoDB来确保这些任务中只有一个可以开始下一阶段的处理 我有以下代码,旨在确保这些任务中只有一个可

我有一个用Java编写的任务工作者,使用MongoDB 3.4副本集,该副本集运行许多线程,每个线程基本上都这样做

  • 运行任务
  • 通过在MongoDB中更新该任务的文档来表示该任务已完成
  • 运行查询以查看此任务集中的所有任务是否都已完成
    • 如果是,请继续下一阶段的处理
    • 否则,什么也不做
正如你可能看到的,这里有一个竞赛条件;多个任务几乎可以同时完成,并且认为它们是最后一个要完成的任务。我想使用MongoDB来确保这些任务中只有一个可以开始下一阶段的处理

我有以下代码,旨在确保这些任务中只有一个可以继续(我使用Jongo与MongoDB接口)

这里很简单;我只是使用findAndModify将芯片组(任务集)的状态更改为排队。成功进行更改的人将执行runNextProcessingStep()

或者这就是我认为它应该起作用的方式。事实上,一些任务,甚至是相隔2秒完成的任务,都会以某种方式返回一个非空的
修改的
。据我所知,MongoDB应该在运行FindModify时锁定文档,这样非空文档最多只能返回一次


我已经阅读并实现了其中所说的一切。我已经将连接写关注点设置为多数,将读关注点设置为线性。我已经在_id和status上创建了一个唯一的复合索引。还是没什么。也许我误解了FindModify的实际行为?我做错了什么?

好吧,这很尴尬,但为了成为一个好的互联网公民,我会把发生的事情告诉大家。还有另一个线程正在从我下面更改状态。我已经说服自己这不可能,但是,好吧,并发有时会是一种真正的痛苦。findAndModify的工作原理正是我所认为的

Chipset modified = chipsets
  .findAndModify("{_id: #, status: {$ne: #}}", new Object[] { chipset.getId(), Chipset.Status.Queued })
  .with("{$set: {status: #}}", new Object[] { Chipset.Status.Queued })
  .returnNew().as(Chipset.class);

if (modified != null)
    runNextProcessingStep();