
org.opalj.concurrent.Locking.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package concurrent
import java.util.concurrent.locks.ReentrantReadWriteLock
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
import org.opalj.collection.immutable.Chain
import org.opalj.collection.immutable.Naught
/**
* A basic facility to model shared and exclusive access to some functionality/data structure.
*
* ==Usage==
* To use this generic locking facility you should mix in this trait.
*
* @author Michael Eichberg
*/
trait Locking {
protected[this] final val rwLock = new ReentrantReadWriteLock()
/**
* Acquires the write lock associated with this instance and then executes the function `f`.
* Afterwards, the lock is released.
*/
@inline protected[this] final def withWriteLock[B](f: ⇒ B): B = Locking.withWriteLock(rwLock)(f)
/**
* Acquires the read lock associated with this instance and then executes the function `f`.
* Afterwards, the lock is released.
*/
@inline protected[this] final def withReadLock[B](f: ⇒ B): B = Locking.withReadLock(rwLock)(f)
}
/**
* Defines several convenience methods related to using `(Reentrant(ReadWrite))Lock`s.
*/
object Locking {
/**
* Acquires the write lock associated with this instance and then executes the function `f`.
* Afterwards, the lock is released.
*/
@inline final def withWriteLock[B](rwLock: ReentrantReadWriteLock)(f: ⇒ B): B = {
val lock = rwLock.writeLock()
var isLocked = false
try {
lock.lock()
isLocked = true
f
} finally {
if (isLocked) lock.unlock()
}
}
/**
* Acquires all given locks in the given order and then executes the given function `f`.
* Afterwards all locks are released in reverse order.
*/
@inline final def withWriteLocks[T](
rwLocks: TraversableOnce[ReentrantReadWriteLock]
)(
f: ⇒ T
): T = {
var acquiredRWLocks: Chain[WriteLock] = Naught
var error: Throwable = null
val allLocked =
rwLocks.forall { rwLock ⇒
try {
val l = rwLock.writeLock
l.lock
acquiredRWLocks :&:= l
true
} catch {
case t: Throwable ⇒
error = t
false
}
}
assert(allLocked || (error ne null))
try {
if (allLocked) {
f
} else {
// If we reach this point, something went so terribly wrong, that the performance
// penalty of throwing an exception and immediately catching it, is a no-brainer...
throw error;
}
} finally {
acquiredRWLocks foreach { rwLock ⇒
try { rwLock.unlock() } catch { case t: Throwable ⇒ if (error eq null) error = t }
}
if (error ne null) throw error;
}
}
/**
* Acquires the read lock and then executes the function `f`.
* Before returning the lock is always released.
*/
@inline final def withReadLock[B](rwLock: ReentrantReadWriteLock)(f: ⇒ B): B = {
val lock = rwLock.readLock()
try {
lock.lock()
f
} finally {
lock.unlock()
}
}
/**
* Tries to acquire the read lock and then executes the function `f`; if the read lock cannot
* be acquired the given function `f` is not executed and `None` is returned.
*
* If lock was acquired, it will always be released before the method returns.
*/
final def tryWithReadLock[B](rwLock: ReentrantReadWriteLock)(f: ⇒ B): Option[B] = {
var isLocked = false
try {
isLocked = rwLock.readLock().tryLock(100L, TimeUnit.MILLISECONDS)
if (isLocked)
Some(f)
else
None
} finally {
if (isLocked) rwLock.readLock().unlock()
}
}
/**
* Acquires the lock and then executes the function `f`.
* Before returning the lock is always released.
*/
@inline final def withLock[B](lock: ReentrantLock)(f: ⇒ B): B = {
try {
lock.lock()
f
} finally {
lock.unlock()
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy