我正在使用一个库,该库的方法如下所示。
trait LibraryDependency {
/**
* This method if called while previous future is not resolved will return a failed future
* @return
*/
def foo(): Future[Boolean]
}
如果foo()
返回的以前的将来尚未完成,则方法foo()
将返回失败的将来。由于我无法修改特征库的实现,因此我尝试用自己的包装器将其包装,以提供所需的行为。
我需要的行为是,如果同时存在对foo()
的调用,则其他期货也会阻塞,直到第一个期货解决。我试图做这样的事情。
class ThreadSafeLibraryWrapper(delegate: LibraryDependency) extends LibraryDependency {
private val lock: Object = new Object
private implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
/**
* This one will block the other concurrent calls to foo()
* @return
*/
override def foo(): Future[Boolean] = {
val promise = Promise[Boolean]()
lock.synchronized {
val result = delegate.foo()
promise.completeWith(result)
result.onComplete { _ =>
lock.notify()
}
lock.wait()
}
promise.future
}
}
我遇到了以下问题,我不确定如何阻止正在调用此方法的线程,并完成原始的将来,所以我得到了IllegalMonitorStateException
。
编辑:我已经通过使用Await
class ThreadSafeLibraryWrapper(delegate: LibraryDependency) extends LibraryDependency {
private val lock: Object = new Object
private implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
/**
* This one will block the other concurrent calls to foo()
* @return
*/
override def foo(): Future[Boolean] = Future {
lock.synchronized {
Await.result(delegate.foo(), Duration.Inf)
}
}
}
我仍然不确定如何避免使用Await
。
答案 0 :(得分:0)
如果我正确理解了您的问题,则您的依赖项可以同时在Future
上运行,因此您希望使用包装器来限制对foo
方法的访问,以免将来返回失败的结果。如果是这样,则看起来您需要排队下一个调用,直到上一个调用完成。
好吧,我做了一些原型设计,希望对您有所帮助:
import java.time.LocalTime.now
import scala.collection.immutable.Queue
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.{Failure, Success, Try}
object Concurrency {
trait LibraryDependency {
/**
* This method if called while previous future is not resolved will return a failed future
* @return
*/
def foo(): Future[Boolean]
}
class DummyLibraryDependency(implicit ec: ExecutionContext) extends LibraryDependency {
override def foo(): Future[Boolean] = {
Future {
println(s"${now()} - started dependency execution")
Thread.sleep(1000)
println(s"${now()} - finished dependency execution")
true
}
}
}
class SafeLibraryDependency(delegate: LibraryDependency)(implicit ec: ExecutionContext) {
private type OnComplete = Try[Boolean] => Unit
private var currentlyRunning: Option[Future[Boolean]] = None
private var queue: Queue[Promise[Boolean]] = Queue[Promise[Boolean]]()
def foo: Future[Boolean] = {
this.synchronized {
currentlyRunning.fold(startDelegateTask(onRunningComplete))(_ => enqueueNextTask())
}
}
private def enqueueNextTask(): Future[Boolean] = {
val promise = Promise[Boolean]()
queue = queue enqueue promise
promise.future
}
private def onRunningComplete(result: Try[Boolean]): Unit = {
this.synchronized {
currentlyRunning = None
if(queue.nonEmpty) {
val (promise, newQueue) = queue.dequeue
queue = newQueue
startDelegateTask { result =>
promise.complete(result)
onRunningComplete(result)
}
}
}
}
private def startDelegateTask(f: OnComplete): Future[Boolean] = {
val task = delegate.foo()
task.onComplete(f)
currentlyRunning = Some(task)
task
}
}
def main(args: Array[String]): Unit = {
import scala.concurrent.ExecutionContext.Implicits.global
val dummyLibraryDependency = new DummyLibraryDependency
val safeLibraryDependency = new SafeLibraryDependency(dummyLibraryDependency)
safeLibraryDependency.foo.onComplete(result => println(s"${now()} - #1 complete with result: $result"))
safeLibraryDependency.foo.onComplete(result => println(s"${now()} - #2 complete with result: $result"))
safeLibraryDependency.foo.onComplete(result => println(s"${now()} - #3 complete with result: $result"))
Thread.sleep(5000)
println("Done")
}
}
所以SafeLibraryDependency
-这是包装器,将调用仅限制为一次运行的Future
。
在我的机器上的输出是下一个:
19:30:43.666 - started dependency execution
19:30:44.679 - finished dependency execution
19:30:44.681 - started dependency execution
19:30:44.679 - #1 complete with result: Success(true)
19:30:45.681 - finished dependency execution
19:30:45.681 - started dependency execution
19:30:45.681 - #2 complete with result: Success(true)
19:30:46.682 - finished dependency execution
19:30:46.682 - #3 complete with result: Success(true)
Done
希望这对您有帮助!