reentrantreadwritelock.java

来自「SRI international 发布的OAA框架软件」· Java 代码 · 共 1,180 行 · 第 1/4 页

JAVA
1,180
字号
/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.backport.java.util.concurrent.locks;

import edu.emory.mathcs.backport.java.util.concurrent.*;
import java.util.*;
import edu.emory.mathcs.backport.java.util.concurrent.helpers.*;

/**
 * An implementation of {@link ReadWriteLock} supporting similar
 * semantics to {@link ReentrantLock}.
 * <p>This class has the following properties:
 *
 * <ul>
 * <li><b>Acquisition order</b>
 *
 * <p>The order of entry to the
 * lock need not be in arrival order. If readers are
 * active and a writer enters the lock then no subsequent readers will
 * be granted the read lock until after that writer has acquired and
 * released the write lock.
 *
 * DEPARTURE FROM java.util.concurrent: this implementation is implemented
 * as writer-preferring and thus its acquisition order may be different
 * than in java.util.concurrent.
 *
 * <li><b>Reentrancy</b>
 * <p>This lock allows both readers and writers to reacquire read or
 * write locks in the style of a {@link ReentrantLock}. Readers are not
 * allowed until all write locks held by the writing thread have been
 * released.
 * <p>Additionally, a writer can acquire the read lock - but not vice-versa.
 * Among other applications, reentrancy can be useful when
 * write locks are held during calls or callbacks to methods that
 * perform reads under read locks.
 * If a reader tries to acquire the write lock it will never succeed.
 *
 * <li><b>Lock downgrading</b>
 * <p>Reentrancy also allows downgrading from the write lock to a read lock,
 * by acquiring the write lock, then the read lock and then releasing the
 * write lock. However, upgrading from a read lock to the write lock is
 * <b>not</b> possible.
 *
 * <li><b>Interruption of lock acquisition</b>
 * <p>The read lock and write lock both support interruption during lock
 * acquisition.
 *
 * <li><b>{@link Condition} support</b>
 * <p>The write lock provides a {@link Condition} implementation that
 * behaves in the same way, with respect to the write lock, as the
 * {@link Condition} implementation provided by
 * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
 * This {@link Condition} can, of course, only be used with the write lock.
 * <p>The read lock does not support a {@link Condition} and
 * <tt>readLock().newCondition()</tt> throws
 * <tt>UnsupportedOperationException</tt>.
 *
 * <li><b>Instrumentation</b>
 * <P> This class supports methods to determine whether locks
 * are held or contended. These methods are designed for monitoring
 * system state, not for synchronization control.
 * </ul>
 *
 * <p> Serialization of this class behaves in the same way as built-in
 * locks: a deserialized lock is in the unlocked state, regardless of
 * its state when serialized.
 *
 * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit
 * reentrancy to perform lock downgrading after updating a cache (exception
 * handling is elided for simplicity):
 * <pre>
 * class CachedData {
 *   Object data;
 *   volatile boolean cacheValid;
 *   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
 *
 *   void processCachedData() {
 *     rwl.readLock().lock();
 *     if (!cacheValid) {
 *        // upgrade lock manually
 *        rwl.readLock().unlock();   // must unlock first to obtain writelock
 *        rwl.writeLock().lock();
 *        if (!cacheValid) { // recheck
 *          data = ...
 *          cacheValid = true;
 *        }
 *        // downgrade lock
 *        rwl.readLock().lock();  // reacquire read without giving up write lock
 *        rwl.writeLock().unlock(); // unlock write, still hold read
 *     }
 *
 *     use(data);
 *     rwl.readLock().unlock();
 *   }
 * }
 * </pre>
 *
 * ReentrantReadWriteLocks can be used to improve concurrency in some
 * uses of some kinds of Collections. This is typically worthwhile
 * only when the collections are expected to be large, accessed by
 * more reader threads than writer threads, and entail operations with
 * overhead that outweighs synchronization overhead. For example, here
 * is a class using a TreeMap that is expected to be large and
 * concurrently accessed.
 *
 * <pre>
 * class RWDictionary {
 *    private final Map&lt;String, Data&gt;  m = new TreeMap&lt;String, Data&gt;();
 *    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
 *    private final Lock r = rwl.readLock();
 *    private final Lock w = rwl.writeLock();
 *
 *    public Data get(String key) {
 *        r.lock(); try { return m.get(key); } finally { r.unlock(); }
 *    }
 *    public String[] allKeys() {
 *        r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); }
 *    }
 *    public Data put(String key, Data value) {
 *        w.lock(); try { return m.put(key, value); } finally { w.unlock(); }
 *    }
 *    public void clear() {
 *        w.lock(); try { m.clear(); } finally { w.unlock(); }
 *    }
 * }
 * </pre>
 *
 *
 * <h3>Implementation Notes</h3>
 *
 * <p>A reentrant write lock intrinsically defines an owner and can
 * only be released by the thread that acquired it.  In contrast, in
 * this implementation, the read lock has no concept of ownership, and
 * there is no requirement that the thread releasing a read lock is
 * the same as the one that acquired it.  However, this property is
 * not guaranteed to hold in future implementations of this class.
 *
 * <p> This lock supports a maximum of 65536 recursive write locks
 * and 65536 read locks. Attempts to exceed these limits result in
 * {@link Error} throws from locking methods.
 *
 * @since 1.5
 * @author Doug Lea
 *
 */
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable  {
    private static final long serialVersionUID = -6992448646407690164L;

    int activeReaders_ = 0;
    Thread activeWriter_ = null;
    int waitingReaders_ = 0;
    int waitingWriters_ = 0;

    final ReaderLock readerLock_ = new ReaderLock();
    final WriterLock writerLock_ = new WriterLock();

    /** Number of acquires on write lock by activeWriter_ thread **/
    int writeHolds_ = 0;

    /** Number of acquires on read lock by any reader thread **/
    HashMap readers_ = new HashMap();

    /** cache/reuse the special Integer value one to speed up readlocks **/
    static final Integer IONE = new Integer(1);

    /**
     * Creates a new <tt>ReentrantReadWriteLock</tt> with
     * default ordering properties.
     */
    public ReentrantReadWriteLock() {}

    public Lock writeLock() { return writerLock_; }
    public Lock readLock()  { return readerLock_; }

    /*
       Each of these variants is needed to maintain atomicity
       of wait counts during wait loops. They could be
       made faster by manually inlining each other. We hope that
       compilers do this for us though.
    */

    synchronized boolean startReadFromNewReader() {
        boolean pass = startRead();
        if (!pass) ++waitingReaders_;
        return pass;
    }

    synchronized boolean startWriteFromNewWriter() {
        boolean pass = startWrite();
        if (!pass) ++waitingWriters_;
        return pass;
    }

    synchronized boolean startReadFromWaitingReader() {
        boolean pass = startRead();
        if (pass) --waitingReaders_;
        return pass;
    }

    synchronized boolean startWriteFromWaitingWriter() {
        boolean pass = startWrite();
        if (pass) --waitingWriters_;
        return pass;
    }

    /*
      A bunch of small synchronized methods are needed
      to allow communication from the Lock objects
      back to this object, that serves as controller
    */


    synchronized void cancelledWaitingReader() { --waitingReaders_; }
    synchronized void cancelledWaitingWriter() { --waitingWriters_; }

    boolean allowReader() {
      return (activeWriter_ == null && waitingWriters_ == 0) ||
        activeWriter_ == Thread.currentThread();
    }

    synchronized boolean startRead() {
        Thread t = Thread.currentThread();
        Object c = readers_.get(t);
        if (c != null) { // already held -- just increment hold count
            readers_.put(t, new Integer( ( (Integer) (c)).intValue() + 1));
            ++activeReaders_;
            return true;
        }
        else if (allowReader()) {
            readers_.put(t, IONE);
            ++activeReaders_;
            return true;
        }
        else
            return false;
    }

    synchronized boolean startWrite() {
        if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
            ++writeHolds_;
            return true;
        }
        else if (writeHolds_ == 0) {
            if (activeReaders_ == 0 ||
                (readers_.size() == 1 &&
                 readers_.get(Thread.currentThread()) != null)) {
                activeWriter_ = Thread.currentThread();
                writeHolds_ = 1;
                return true;
            }
            else
                return false;
        }
        else
            return false;
    }

    synchronized Signaller endRead() {
        Thread t = Thread.currentThread();
        Object c = readers_.get(t);
        if (c == null)
            throw new IllegalThreadStateException();
        --activeReaders_;
        if (c != IONE) { // more than one hold; decrement count
            int h = ( (Integer) (c)).intValue() - 1;
            Integer ih = (h == 1) ? IONE : new Integer(h);
            readers_.put(t, ih);
            return null;
        }
        else {
            readers_.remove(t);

            if (writeHolds_ > 0) // a write lock is still held by current thread
                return null;
            else if (activeReaders_ == 0 && waitingWriters_ > 0)
                return writerLock_;
            else
                return null;
        }
    }

    synchronized Signaller endWrite() {
        if (activeWriter_ != Thread.currentThread()) {
            throw new IllegalMonitorStateException();
        }
        --writeHolds_;
        if (writeHolds_ > 0) // still being held
            return null;
        else {
            activeWriter_ = null;
            if (waitingReaders_ > 0 && allowReader())

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?