Scala Play线程

时间:2016-06-02 02:29:17

标签: multithreading mongodb scala future

我目前正在使用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。 我怎么能这样做?

2 个答案:

答案 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)

您可以使用SemaphoreReentrantLock来实施锁定:

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
}