Мой коллега сказал следующее об использовании Java ReentrantReadWriteLock
в некотором коде Scala:
Получение блокировки здесь рискованно.Это «реентерабельный», но это внутренне зависит от контекста потока.F
может запускать разные этапы одного и того же вычисления в разных потоках.Вы можете легко вызвать тупик.
F
здесь относится к некоторой эффектной монаде.
По сути, я пытаюсь получить один и тот же повторяющийся замок дважды, в пределахта же самая монада.
Может кто-нибудь уточнить, почему это может быть проблемой?
Код разбит на два файла.Самый внешний:
val lock: Resource[F, Unit] = for {
// some other resource
_ <- store.writeLock
} yield ()
lock.use { _ =>
for {
// stuff
_ <- EitherT(store.doSomething())
// other stuff
} yield ()
}
Затем в store
:
import java.util.concurrent.locks.{Lock, ReentrantReadWriteLock}
import cats.effect.{Resource, Sync}
private def lockAsResource[F[_]](lock: Lock)(implicit F: Sync[F]): Resource[F, Unit] =
Resource.make {
F.delay(lock.lock())
} { _ =>
F.delay(lock.unlock())
}
private val lock = new ReentrantReadWriteLock
val writeLock: Resource[F, Unit] = lockAsResource(lock.writeLock())
def doSomething(): F[Either[Throwable, Unit]] = writeLock.use { _ =>
// etc etc
}
writeLock
в двух частях кода одинаков, и это cats.effect.Resource[F, Unit]
упаковка ReentrantReadWriteLock
х writeLock
.Есть несколько причин, почему я писал код таким образом, поэтому я не хотел бы углубляться в это.Я просто хотел бы понять, почему (по крайней мере, по мнению моего коллеги) это может привести к поломке.
Кроме того, я хотел бы знать, есть ли в Scala какая-то альтернатива, которая позволила бы что-то подобноебез риска тупиков.