All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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