Files
odc-analyzer/app/com/ysoft/concurrent/FutureLock.scala
2016-02-19 12:55:06 +01:00

41 lines
1.3 KiB
Scala

package com.ysoft.concurrent
import java.util.concurrent.atomic.AtomicBoolean
import scala.concurrent.{ExecutionContext, Future}
trait FutureLock[T] {
def whenLocked(cannotLock: => Future[T])(implicit executionContext: ExecutionContext): Future[T]
}
object FutureLock {
def futureLock[T](lock: AtomicBoolean)(f: => Future[T]): FutureLock[T] = new FutureLock[T]() {
override def whenLocked(cannotLock: => Future[T])(implicit executionContext: ExecutionContext): Future[T] = {
if (lock.compareAndSet(/*expect = */ false, /*update = */ true)) {
try {
f.andThen { case _ =>
val wasLocked = lock.getAndSet(false)
if (!wasLocked) {
throw new RuntimeException("The lock was not being held when trying to unlock")
}
}
} catch {
case e: Throwable =>
// So, the Exception was raised before creation of the Future. As a result, the Future will not relase the lock.
// In other words, its our responsibility to release the lock:
val wasLocked = lock.getAndSet(false)
if (!wasLocked) {
throw new RuntimeException("The lock was not being held when throwing the following exception", e)
}
throw e
}
} else {
cannotLock
}
}
}
}