我有一个用 Java 编写的任务工作线程,并使用 MongoDB 3.4 副本集运行许多线程,每个线程基本上都执行此操作。
正如您可能看到的,这里存在竞争条件;多个任务可以几乎同时完成,并认为它们是最后完成的任务。我想使用 MongoDB 来确保只允许其中一个任务开始下一阶段的处理。
我有以下代码,旨在确保只有其中一项任务可以继续(我正在使用 Jongo 与 MongoDB 交互)。
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();
Run Code Online (Sandbox Code Playgroud)
这里很简单;我只是使用 findAndModify 将芯片组(任务集)的状态更改为“已排队”。成功进行更改的人将执行 runNextProcessingStep()。
或者我认为这应该是这样的。实际上,有几个任务,即使是相隔 2 秒完成的任务,也会以某种方式返回非 null modified。据我了解,MongoDB 应该在运行 findAndModify 时锁定文档,以便非空文档只能返回一次。
我已经通过findAndModify阅读了线性化读取并实现了其中所说的所有内容。我已将连接写入关注点设置为“多数”,将读取关注点设置为“线性化”。我在 _id 和 status 上创建了一个唯一的复合索引。依然没有。也许我误解了 findAndModify 的实际行为?我究竟做错了什么?
好吧,这很尴尬,但为了成为一名优秀的互联网公民,我将更新所发生的事情。还有另一个线程正在从我下面改变状态。我说服自己事实并非如此,但是,并发有时确实很痛苦。findAndModify 的工作原理与我想象的完全一样。