我目前正在使用Scala / Play2框架/ MongoDB(reactivemongo) 我在请求中有一个函数,如下所示:在集合中查找最大值,随机增加该最大值,并将新值保存到该集合,并返回新值。
def generateCode():Future[String] = {
// find maximum
maximum = Future[].... map { maxValue =>
// increase maxValue
newValue = maxValue + random
// save back to database
}
}
问题是我希望这段代码一次只运行1个线程。因为如果2个线程同时运行,那么值会发生冲突。 例: 线程1:读取max = 100,线程2读取max = 100 线程1:增加max = 105,线程2增加max = 102 线程1:将105保存到db,线程2将102保存到db
最后db中的最大值是102,实际上它应该是105。 我怎么能这样做?
答案 0 :(得分:0)
作为规则,ReactiveMongo API和Future上的操作需要在范围内隐式ExecutionContext。因此,您可以做的是定义单个线程执行上下文,并在您定义generateCode()
方法的类中以及在您调用ReactiveMongo API的类中使用它。
import java.util.concurrent.Executors
implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(Executors.newSingleThreadExecutor())
您还可以将ec
显式传递给需要隐式ExecutionContext的方法。您只需要确保整个异步方法调用链使用相同的单线程执行上下文。
答案 1 :(得分:0)
您可以使用Semaphore
或ReentrantLock
来实施锁定:
val s = new ReentrantLock()
def generateCode():Future[String] = {
s.lock() //get lock block other threads to execute the db operation
// find maximum
maximum = Future[].... map { maxValue =>
// increase maxValue
newValue = maxValue + random
// save back to database
}
s.unlock()///after finish db operation, release this lock for other threads can get the Semaphore to continue work
}