Return-Path: Delivered-To: apmail-harmony-commits-archive@www.apache.org Received: (qmail 55703 invoked from network); 28 Jul 2009 09:31:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 28 Jul 2009 09:31:01 -0000 Received: (qmail 63680 invoked by uid 500); 28 Jul 2009 09:32:18 -0000 Delivered-To: apmail-harmony-commits-archive@harmony.apache.org Received: (qmail 63628 invoked by uid 500); 28 Jul 2009 09:32:18 -0000 Mailing-List: contact commits-help@harmony.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@harmony.apache.org Delivered-To: mailing list commits@harmony.apache.org Received: (qmail 63619 invoked by uid 99); 28 Jul 2009 09:32:18 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Jul 2009 09:32:18 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Jul 2009 09:32:12 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 19A3823889EA; Tue, 28 Jul 2009 09:31:00 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r798469 [20/28] - in /harmony/enhanced/classlib/branches/java6: ./ depends/build/platform/ depends/files/ depends/jars/ depends/manifests/icu4j_4.0/ depends/manifests/icu4j_4.2.1/ depends/manifests/icu4j_4.2.1/META-INF/ make/ modules/access... Date: Tue, 28 Jul 2009 09:30:48 -0000 To: commits@harmony.apache.org From: hindessm@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090728093100.19A3823889EA@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java Tue Jul 28 09:30:33 2009 @@ -19,32 +19,60 @@ * *

This class does not impose a reader or writer preference * ordering for lock access. However, it does support an optional - * fairness policy. When constructed as fair, threads - * contend for entry using an approximately arrival-order policy. When - * the write lock is released either the longest-waiting single writer - * will be assigned the write lock, or if there is a reader waiting - * longer than any writer, the set of readers will be assigned the - * read lock. When constructed as non-fair, the order of entry to the - * lock need not be in arrival order. In either case, 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. - * + * fairness policy. + * + *

+ *
Non-fair mode (default) + *
When constructed as non-fair (the default), the order of entry + * to the read and write lock is unspecified, subject to reentrancy + * constraints. A nonfair lock that is continuously contended may + * indefinitely postpone one or more reader or writer threads, but + * will normally have higher throughput than a fair lock. + *

+ * + *

Fair mode + *
When constructed as fair, threads contend for entry using an + * approximately arrival-order policy. When the currently held lock + * is released either the longest-waiting single writer thread will + * be assigned the write lock, or if there is a group of reader threads + * waiting longer than all waiting writer threads, that group will be + * assigned the read lock. + * + *

A thread that tries to acquire a fair read lock (non-reentrantly) + * will block if either the write lock is held, or there is a waiting + * writer thread. The thread will not acquire the read lock until + * after the oldest currently waiting writer thread has acquired and + * released the write lock. Of course, if a waiting writer abandons + * its wait, leaving one or more reader threads as the longest waiters + * in the queue with the write lock free, then those readers will be + * assigned the read lock. + * + *

A thread that tries to acquire a fair write lock (non-reentrantly) + * will block unless both the read lock and write lock are free (which + * implies there are no waiting threads). (Note that the non-blocking + * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods + * do not honor this fair setting and will acquire the lock if it is + * possible, regardless of waiting threads.) + *

+ *

+ * *
  • Reentrancy + * *

    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. - *

    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. - * + * write locks in the style of a {@link ReentrantLock}. Non-reentrant + * readers are not allowed until all write locks held by the writing + * thread have been released. + * + *

    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. + * *

  • Lock downgrading *

    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 + * write lock. However, upgrading from a read lock to the write lock is * not possible. * *

  • Interruption of lock acquisition @@ -53,96 +81,105 @@ * *
  • {@link Condition} support *

    The write lock provides a {@link Condition} implementation that - * behaves in the same way, with respect to the write lock, as the + * 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. + * *

    The read lock does not support a {@link Condition} and - * readLock().newCondition() throws - * UnsupportedOperationException. + * {@code readLock().newCondition()} throws + * {@code UnsupportedOperationException}. * *

  • Instrumentation - *

    This class supports methods to determine whether locks + *

    This class supports methods to determine whether locks * are held or contended. These methods are designed for monitoring * system state, not for synchronization control. * * - *

    Serialization of this class behaves in the same way as built-in + *

    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. * - *

    Sample usages. Here is a code sketch showing how to exploit - * reentrancy to perform lock downgrading after updating a cache (exception - * handling is elided for simplicity): - *

    + * 

    Sample usages. Here is a code sketch showing how to perform + * lock downgrading after updating a cache (exception handling is + * particularly tricky when handling multiple locks in a non-nested + * fashion): + * + *

     {@code
      * class CachedData {
      *   Object data;
      *   volatile boolean cacheValid;
    - *   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    + *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      *
      *   void processCachedData() {
      *     rwl.readLock().lock();
      *     if (!cacheValid) {
    - *        // upgrade lock manually
    - *        rwl.readLock().unlock();   // must unlock first to obtain writelock
    + *        // Must release read lock before acquiring write lock
    + *        rwl.readLock().unlock();
      *        rwl.writeLock().lock();
    - *        if (!cacheValid) { // recheck
    - *          data = ...
    - *          cacheValid = true;
    + *        try {
    + *          // Recheck state because another thread might have
    + *          // acquired write lock and changed state before we did.
    + *          if (!cacheValid) {
    + *            data = ...
    + *            cacheValid = true;
    + *          }
    + *          // Downgrade by acquiring read lock before releasing write lock
    + *          rwl.readLock().lock();
    + *        } finally  {
    + *          rwl.writeLock().unlock(); // Unlock write, still hold read
      *        }
    - *        // 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();
    + *     try {
    + *       use(data);
    + *     } finally {
    + *       rwl.readLock().unlock();
    + *     }
      *   }
    - * }
    - * 
    + * }}
    * * 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 + * is a class using a TreeMap that is expected to be large and * concurrently accessed. * - *
    + * 
    {@code
      * class RWDictionary {
    - *    private final Map<String, Data>  m = new TreeMap<String, Data>();
    + *    private final Map m = new TreeMap();
      *    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(); }
    + *        r.lock();
    + *        try { return m.get(key); }
    + *        finally { r.unlock(); }
      *    }
      *    public String[] allKeys() {
    - *        r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); }
    + *        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(); }
    + *        w.lock();
    + *        try { return m.put(key, value); }
    + *        finally { w.unlock(); }
      *    }
      *    public void clear() {
    - *        w.lock(); try { m.clear(); } finally { w.unlock(); }
    + *        w.lock();
    + *        try { m.clear(); }
    + *        finally { w.unlock(); }
      *    }
    - * }
    - * 
    - * + * }}
    * *

    Implementation Notes

    * - *

    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. - * - *

    This lock supports a maximum of 65536 recursive write locks - * and 65536 read locks. Attempts to exceed these limits result in + *

    This lock supports a maximum of 65535 recursive write locks + * and 65535 read locks. Attempts to exceed these limits result in * {@link Error} throws from locking methods. * * @since 1.5 @@ -156,26 +193,24 @@ /** Inner class providing writelock */ private final ReentrantReadWriteLock.WriteLock writerLock; /** Performs all synchronization mechanics */ - private final Sync sync; + final Sync sync; /** - * Creates a new ReentrantReadWriteLock with - * default ordering properties. + * Creates a new {@code ReentrantReadWriteLock} with + * default (nonfair) ordering properties. */ public ReentrantReadWriteLock() { - sync = new NonfairSync(); - readerLock = new ReadLock(this); - writerLock = new WriteLock(this); + this(false); } /** - * Creates a new ReentrantReadWriteLock with + * Creates a new {@code ReentrantReadWriteLock} with * the given fairness policy. * - * @param fair true if this lock should use a fair ordering policy + * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantReadWriteLock(boolean fair) { - sync = (fair)? new FairSync() : new NonfairSync(); + sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } @@ -183,129 +218,409 @@ public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } - /* - * Read vs write count extraction constants and functions. - * Lock state is logically divided into two shorts: The lower - * one representing the exclusive (writer) lock hold count, - * and the upper the shared (reader) hold count. - */ - - static final int SHARED_SHIFT = 16; - static final int SHARED_UNIT = (1 << SHARED_SHIFT); - static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; - - /** Returns the number of shared holds represented in count */ - static int sharedCount(int c) { return c >>> SHARED_SHIFT; } - /** Returns the number of exclusive holds represented in count */ - static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } - - /** + /** * Synchronization implementation for ReentrantReadWriteLock. * Subclassed into fair and nonfair versions. */ - abstract static class Sync extends AbstractQueuedSynchronizer { - /** Current (exclusive) owner thread */ - transient Thread owner; + static abstract class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 6317671515068378041L; + + /* + * Read vs write count extraction constants and functions. + * Lock state is logically divided into two unsigned shorts: + * The lower one representing the exclusive (writer) lock hold count, + * and the upper the shared (reader) hold count. + */ + + static final int SHARED_SHIFT = 16; + static final int SHARED_UNIT = (1 << SHARED_SHIFT); + static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; + static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; + + /** Returns the number of shared holds represented in count */ + static int sharedCount(int c) { return c >>> SHARED_SHIFT; } + /** Returns the number of exclusive holds represented in count */ + static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } /** - * Perform write lock. Allows fast path in non-fair version. + * A counter for per-thread read hold counts. + * Maintained as a ThreadLocal; cached in cachedHoldCounter */ - abstract void wlock(); + static final class HoldCounter { + int count = 0; + // Use id, not reference, to avoid garbage retention + final long tid = Thread.currentThread().getId(); + } - /** - * Perform non-fair tryLock for write. tryAcquire is - * implemented in subclasses, but both versions need nonfair - * try for trylock method + /** + * ThreadLocal subclass. Easiest to explicitly define for sake + * of deserialization mechanics. */ - final boolean nonfairTryAcquire(int acquires) { - // mask out readlocks if called from condition methods - acquires = exclusiveCount(acquires); + static final class ThreadLocalHoldCounter + extends ThreadLocal { + public HoldCounter initialValue() { + return new HoldCounter(); + } + } + + /** + * The number of reentrant read locks held by current thread. + * Initialized only in constructor and readObject. + * Removed whenever a thread's read hold count drops to 0. + */ + private transient ThreadLocalHoldCounter readHolds; + + /** + * The hold count of the last thread to successfully acquire + * readLock. This saves ThreadLocal lookup in the common case + * where the next thread to release is the last one to + * acquire. This is non-volatile since it is just used + * as a heuristic, and would be great for threads to cache. + * + *

    Can outlive the Thread for which it is caching the read + * hold count, but avoids garbage retention by not retaining a + * reference to the Thread. + * + *

    Accessed via a benign data race; relies on the memory + * model's final field and out-of-thin-air guarantees. + */ + private transient HoldCounter cachedHoldCounter; + + /** + * firstReader is the first thread to have acquired the read lock. + * firstReaderHoldCount is firstReader's hold count. + * + *

    More precisely, firstReader is the unique thread that last + * changed the shared count from 0 to 1, and has not released the + * read lock since then; null if there is no such thread. + * + *

    Cannot cause garbage retention unless the thread terminated + * without relinquishing its read locks, since tryReleaseShared + * sets it to null. + * + *

    Accessed via a benign data race; relies on the memory + * model's out-of-thin-air guarantees for references. + * + *

    This allows tracking of read holds for uncontended read + * locks to be very cheap. + */ + private transient Thread firstReader = null; + private transient int firstReaderHoldCount; + + Sync() { + readHolds = new ThreadLocalHoldCounter(); + setState(getState()); // ensures visibility of readHolds + } + + /* + * Acquires and releases use the same code for fair and + * nonfair locks, but differ in whether/how they allow barging + * when queues are non-empty. + */ + + /** + * Returns true if the current thread, when trying to acquire + * the read lock, and otherwise eligible to do so, should block + * because of policy for overtaking other waiting threads. + */ + abstract boolean readerShouldBlock(); + + /** + * Returns true if the current thread, when trying to acquire + * the write lock, and otherwise eligible to do so, should block + * because of policy for overtaking other waiting threads. + */ + abstract boolean writerShouldBlock(); + + /* + * Note that tryRelease and tryAcquire can be called by + * Conditions. So it is possible that their arguments contain + * both read and write holds that are all released during a + * condition wait and re-established in tryAcquire. + */ + + protected final boolean tryRelease(int releases) { + if (!isHeldExclusively()) + throw new IllegalMonitorStateException(); + int nextc = getState() - releases; + boolean free = exclusiveCount(nextc) == 0; + if (free) + setExclusiveOwnerThread(null); + setState(nextc); + return free; + } + + protected final boolean tryAcquire(int acquires) { + /* + * Walkthrough: + * 1. If read count nonzero or write count nonzero + * and owner is a different thread, fail. + * 2. If count would saturate, fail. (This can only + * happen if count is already nonzero.) + * 3. Otherwise, this thread is eligible for lock if + * it is either a reentrant acquire or + * queue policy allows it. If so, update state + * and set owner. + */ Thread current = Thread.currentThread(); int c = getState(); int w = exclusiveCount(c); - if (w + acquires >= SHARED_UNIT) - throw new Error("Maximum lock count exceeded"); - if (c != 0 && (w == 0 || current != owner)) - return false; - if (!compareAndSetState(c, c + acquires)) + if (c != 0) { + // (Note: if c != 0 and w == 0 then shared count != 0) + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w + exclusiveCount(acquires) > MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + // Reentrant acquire + setState(c + acquires); + return true; + } + if (writerShouldBlock() || + !compareAndSetState(c, c + acquires)) return false; - owner = current; + setExclusiveOwnerThread(current); return true; } - /** - * Perform nonfair tryLock for read. + protected final boolean tryReleaseShared(int unused) { + Thread current = Thread.currentThread(); + if (firstReader == current) { + // assert firstReaderHoldCount > 0; + if (firstReaderHoldCount == 1) + firstReader = null; + else + firstReaderHoldCount--; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + int count = rh.count; + if (count <= 1) { + readHolds.remove(); + if (count <= 0) + throw unmatchedUnlockException(); + } + --rh.count; + } + for (;;) { + int c = getState(); + int nextc = c - SHARED_UNIT; + if (compareAndSetState(c, nextc)) + // Releasing the read lock has no effect on readers, + // but it may allow waiting writers to proceed if + // both read and write locks are now free. + return nextc == 0; + } + } + + private IllegalMonitorStateException unmatchedUnlockException() { + return new IllegalMonitorStateException( + "attempt to unlock read lock, not locked by current thread"); + } + + protected final int tryAcquireShared(int unused) { + /* + * Walkthrough: + * 1. If write lock held by another thread, fail. + * 2. Otherwise, this thread is eligible for + * lock wrt state, so ask if it should block + * because of queue policy. If not, try + * to grant by CASing state and updating count. + * Note that step does not check for reentrant + * acquires, which is postponed to full version + * to avoid having to check hold count in + * the more typical non-reentrant case. + * 3. If step 2 fails either because thread + * apparently not eligible or CAS fails or count + * saturated, chain to version with full retry loop. + */ + Thread current = Thread.currentThread(); + int c = getState(); + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return -1; + int r = sharedCount(c); + if (!readerShouldBlock() && + r < MAX_COUNT && + compareAndSetState(c, c + SHARED_UNIT)) { + if (r == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + } + return 1; + } + return fullTryAcquireShared(current); + } + + /** + * Full version of acquire for reads, that handles CAS misses + * and reentrant reads not dealt with in tryAcquireShared. */ - final int nonfairTryAcquireShared(int acquires) { + final int fullTryAcquireShared(Thread current) { + /* + * This code is in part redundant with that in + * tryAcquireShared but is simpler overall by not + * complicating tryAcquireShared with interactions between + * retries and lazily reading hold counts. + */ + HoldCounter rh = null; for (;;) { int c = getState(); - int nextc = c + (acquires << SHARED_SHIFT); - if (nextc < c) + if (exclusiveCount(c) != 0) { + if (getExclusiveOwnerThread() != current) + return -1; + // else we hold the exclusive lock; blocking here + // would cause deadlock. + } else if (readerShouldBlock()) { + // Make sure we're not acquiring read lock reentrantly + if (firstReader == current) { + // assert firstReaderHoldCount > 0; + } else { + if (rh == null) { + rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) { + rh = readHolds.get(); + if (rh.count == 0) + readHolds.remove(); + } + } + if (rh.count == 0) + return -1; + } + } + if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); - if (exclusiveCount(c) != 0 && - owner != Thread.currentThread()) - return -1; - if (compareAndSetState(c, nextc)) + if (compareAndSetState(c, c + SHARED_UNIT)) { + if (sharedCount(c) == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + if (rh == null) + rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + cachedHoldCounter = rh; // cache for release + } return 1; - // Recheck count if lost CAS + } } } - protected final boolean tryRelease(int releases) { + /** + * Performs tryLock for write, enabling barging in both modes. + * This is identical in effect to tryAcquire except for lack + * of calls to writerShouldBlock. + */ + final boolean tryWriteLock() { Thread current = Thread.currentThread(); int c = getState(); - if (owner != current) - throw new IllegalMonitorStateException(); - int nextc = c - releases; - boolean free = false; - if (exclusiveCount(c) == releases) { - free = true; - owner = null; + if (c != 0) { + int w = exclusiveCount(c); + if (w == 0 || current != getExclusiveOwnerThread()) + return false; + if (w == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); } - setState(nextc); - return free; + if (!compareAndSetState(c, c + 1)) + return false; + setExclusiveOwnerThread(current); + return true; } - protected final boolean tryReleaseShared(int releases) { + /** + * Performs tryLock for read, enabling barging in both modes. + * This is identical in effect to tryAcquireShared except for + * lack of calls to readerShouldBlock. + */ + final boolean tryReadLock() { + Thread current = Thread.currentThread(); for (;;) { int c = getState(); - int nextc = c - (releases << SHARED_SHIFT); - if (nextc < 0) - throw new IllegalMonitorStateException(); - if (compareAndSetState(c, nextc)) - return nextc == 0; + if (exclusiveCount(c) != 0 && + getExclusiveOwnerThread() != current) + return false; + int r = sharedCount(c); + if (r == MAX_COUNT) + throw new Error("Maximum lock count exceeded"); + if (compareAndSetState(c, c + SHARED_UNIT)) { + if (r == 0) { + firstReader = current; + firstReaderHoldCount = 1; + } else if (firstReader == current) { + firstReaderHoldCount++; + } else { + HoldCounter rh = cachedHoldCounter; + if (rh == null || rh.tid != current.getId()) + cachedHoldCounter = rh = readHolds.get(); + else if (rh.count == 0) + readHolds.set(rh); + rh.count++; + } + return true; + } } } - + protected final boolean isHeldExclusively() { - return exclusiveCount(getState()) != 0 && - owner == Thread.currentThread(); + // While we must in general read state before owner, + // we don't need to do so to check if current thread is owner + return getExclusiveOwnerThread() == Thread.currentThread(); } // Methods relayed to outer class - - final ConditionObject newCondition() { - return new ConditionObject(); + + final ConditionObject newCondition() { + return new ConditionObject(); } final Thread getOwner() { - int c = exclusiveCount(getState()); - Thread o = owner; - return (c == 0)? null : o; + // Must read state before owner to ensure memory consistency + return ((exclusiveCount(getState()) == 0)? + null : + getExclusiveOwnerThread()); } - + final int getReadLockCount() { return sharedCount(getState()); } - + final boolean isWriteLocked() { return exclusiveCount(getState()) != 0; } final int getWriteHoldCount() { - int c = exclusiveCount(getState()); - Thread o = owner; - return (o == Thread.currentThread())? c : 0; + return isHeldExclusively() ? exclusiveCount(getState()) : 0; + } + + final int getReadHoldCount() { + if (getReadLockCount() == 0) + return 0; + + Thread current = Thread.currentThread(); + if (firstReader == current) + return firstReaderHoldCount; + + HoldCounter rh = cachedHoldCounter; + if (rh != null && rh.tid == current.getId()) + return rh.count; + + int count = readHolds.get().count; + if (count == 0) readHolds.remove(); + return count; } /** @@ -315,78 +630,43 @@ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); + readHolds = new ThreadLocalHoldCounter(); setState(0); // reset to unlocked state } final int getCount() { return getState(); } } - /** + /** * Nonfair version of Sync */ final static class NonfairSync extends Sync { - protected final boolean tryAcquire(int acquires) { - return nonfairTryAcquire(acquires); - } - - protected final int tryAcquireShared(int acquires) { - return nonfairTryAcquireShared(acquires); - } - - // Use fastpath for main write lock method - final void wlock() { - if (compareAndSetState(0, 1)) - owner = Thread.currentThread(); - else - acquire(1); + private static final long serialVersionUID = -8159625535654395037L; + final boolean writerShouldBlock() { + return false; // writers can always barge + } + final boolean readerShouldBlock() { + /* As a heuristic to avoid indefinite writer starvation, + * block if the thread that momentarily appears to be head + * of queue, if one exists, is a waiting writer. This is + * only a probabilistic effect since a new reader will not + * block if there is a waiting writer behind other enabled + * readers that have not yet drained from the queue. + */ + return apparentlyFirstQueuedIsExclusive(); } } - /** + /** * Fair version of Sync */ final static class FairSync extends Sync { - protected final boolean tryAcquire(int acquires) { - // mask out readlocks if called from condition methods - acquires = exclusiveCount(acquires); - Thread current = Thread.currentThread(); - Thread first; - int c = getState(); - int w = exclusiveCount(c); - if (w + acquires >= SHARED_UNIT) - throw new Error("Maximum lock count exceeded"); - if ((w == 0 || current != owner) && - (c != 0 || - ((first = getFirstQueuedThread()) != null && - first != current))) - return false; - if (!compareAndSetState(c, c + acquires)) - return false; - owner = current; - return true; - } - - protected final int tryAcquireShared(int acquires) { - Thread current = Thread.currentThread(); - for (;;) { - Thread first = getFirstQueuedThread(); - if (first != null && first != current) - return -1; - int c = getState(); - int nextc = c + (acquires << SHARED_SHIFT); - if (nextc < c) - throw new Error("Maximum lock count exceeded"); - if (exclusiveCount(c) != 0 && - owner != Thread.currentThread()) - return -1; - if (compareAndSetState(c, nextc)) - return 1; - // Recheck count if lost CAS - } + private static final long serialVersionUID = -2274990926593161451L; + final boolean writerShouldBlock() { + return hasQueuedPredecessors(); } - - final void wlock() { // no fast path - acquire(1); + final boolean readerShouldBlock() { + return hasQueuedPredecessors(); } } @@ -396,46 +676,47 @@ public static class ReadLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; private final Sync sync; - - /** - * Constructor for use by subclasses. + + /** + * Constructor for use by subclasses + * * @param lock the outer lock object - * @throws NullPointerException if lock null + * @throws NullPointerException if the lock is null */ protected ReadLock(ReentrantReadWriteLock lock) { sync = lock.sync; } /** - * Acquires the shared lock. + * Acquires the read lock. * - *

    Acquires the lock if it is not held exclusively by + *

    Acquires the read lock if the write lock is not held by * another thread and returns immediately. * - *

    If the lock is held exclusively by another thread then + *

    If the write lock is held by another thread then * the current thread becomes disabled for thread scheduling - * purposes and lies dormant until the lock has been acquired. + * purposes and lies dormant until the read lock has been acquired. */ - public void lock() { + public void lock() { sync.acquireShared(1); } /** - * Acquires the shared lock unless the current thread is - * {@link Thread#interrupt interrupted}. + * Acquires the read lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. * - *

    Acquires the shared lock if it is not held exclusively + *

    Acquires the read lock if the write lock is not held * by another thread and returns immediately. * - *

    If the lock is held by another thread then the - * current thread becomes disabled for thread scheduling + *

    If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling * purposes and lies dormant until one of two things happens: * *

      * - *
    • The lock is acquired by the current thread; or + *
    • The read lock is acquired by the current thread; or * - *
    • Some other thread {@link Thread#interrupt interrupts} + *
    • Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. * *
    @@ -444,10 +725,10 @@ * *
      * - *
    • has its interrupted status set on entry to this method; or + *
    • has its interrupted status set on entry to this method; or * - *
    • is {@link Thread#interrupt interrupted} while acquiring - * the lock, + *
    • is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, * *
    * @@ -466,83 +747,83 @@ } /** - * Acquires the shared lock only if it is not held exclusively by + * Acquires the read lock only if the write lock is not held by * another thread at the time of invocation. * - *

    Acquires the lock if it is not held exclusively by + *

    Acquires the read lock if the write lock is not held by * another thread and returns immediately with the value - * true. Even when this lock has been set to use a - * fair ordering policy, a call to tryLock() - * will immediately acquire the lock if it is + * {@code true}. Even when this lock has been set to use a + * fair ordering policy, a call to {@code tryLock()} + * will immediately acquire the read lock if it is * available, whether or not other threads are currently - * waiting for the lock. This "barging" behavior + * waiting for the read lock. This "barging" behavior * can be useful in certain circumstances, even though it * breaks fairness. If you want to honor the fairness setting * for this lock, then use {@link #tryLock(long, TimeUnit) * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent * (it also detects interruption). * - *

    If the lock is held exclusively by another thread then + *

    If the write lock is held by another thread then * this method will return immediately with the value - * false. + * {@code false}. * - * @return true if the lock was acquired. + * @return {@code true} if the read lock was acquired */ public boolean tryLock() { - return sync.nonfairTryAcquireShared(1) >= 0; + return sync.tryReadLock(); } /** - * Acquires the shared lock if it is not held exclusively by + * Acquires the read lock if the write lock is not held by * another thread within the given waiting time and the - * current thread has not been {@link Thread#interrupt + * current thread has not been {@linkplain Thread#interrupt * interrupted}. * - *

    Acquires the lock if it is not held exclusively by + *

    Acquires the read lock if the write lock is not held by * another thread and returns immediately with the value - * true. If this lock has been set to use a fair + * {@code true}. If this lock has been set to use a fair * ordering policy then an available lock will not be * acquired if any other threads are waiting for the * lock. This is in contrast to the {@link #tryLock()} - * method. If you want a timed tryLock that does + * method. If you want a timed {@code tryLock} that does * permit barging on a fair lock then combine the timed and * un-timed forms together: * *

    if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
              * 
    * - *

    If the lock is held exclusively by another thread then the - * current thread becomes disabled for thread scheduling + *

    If the write lock is held by another thread then the + * current thread becomes disabled for thread scheduling * purposes and lies dormant until one of three things happens: * *

      * - *
    • The lock is acquired by the current thread; or + *
    • The read lock is acquired by the current thread; or * - *
    • Some other thread {@link Thread#interrupt interrupts} the current - * thread; or + *
    • Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or * - *
    • The specified waiting time elapses + *
    • The specified waiting time elapses. * *
    * - *

    If the lock is acquired then the value true is + *

    If the read lock is acquired then the value {@code true} is * returned. * *

    If the current thread: * *

      * - *
    • has its interrupted status set on entry to this method; or + *
    • has its interrupted status set on entry to this method; or * - *
    • is {@link Thread#interrupt interrupted} while acquiring - * the lock, + *
    • is {@linkplain Thread#interrupt interrupted} while + * acquiring the read lock, * *
    then {@link InterruptedException} is thrown and the * current thread's interrupted status is cleared. * *

    If the specified waiting time elapses then the value - * false is returned. If the time is less than or + * {@code false} is returned. If the time is less than or * equal to zero, the method will not wait at all. * *

    In this implementation, as this method is an explicit @@ -550,13 +831,11 @@ * the interrupt over normal or reentrant acquisition of the * lock, and over reporting the elapse of the waiting time. * - * @param timeout the time to wait for the lock + * @param timeout the time to wait for the read lock * @param unit the time unit of the timeout argument - * - * @return true if the lock was acquired. - * + * @return {@code true} if the read lock was acquired * @throws InterruptedException if the current thread is interrupted - * @throws NullPointerException if unit is null + * @throws NullPointerException if the time unit is null * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -564,20 +843,19 @@ } /** - * Attempts to release this lock. + * Attempts to release this lock. * *

    If the number of readers is now zero then the lock - * is made available for other lock attempts. + * is made available for write lock attempts. */ public void unlock() { sync.releaseShared(1); } /** - * Throws UnsupportedOperationException because ReadLocks - * do not support conditions. - * @return A new {@link Condition} instance for this Lock - * instance. + * Throws {@code UnsupportedOperationException} because + * {@code ReadLocks} do not support conditions. + * * @throws UnsupportedOperationException always */ public Condition newCondition() { @@ -586,17 +864,16 @@ /** * Returns a string identifying this lock, as well as its lock state. - * The state, in brackets, includes the String - * "Read locks =" followed by the number of held - * read locks. - * @return a string identifying this lock, as well as its lock state. + * The state, in brackets, includes the String {@code "Read locks ="} + * followed by the number of held read locks. + * + * @return a string identifying this lock, as well as its lock state */ public String toString() { int r = sync.getReadLockCount(); - return super.toString() + + return super.toString() + "[Read locks = " + r + "]"; } - } /** @@ -605,42 +882,45 @@ public static class WriteLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; private final Sync sync; - - /** - * Constructor for use by subclasses. + + /** + * Constructor for use by subclasses + * * @param lock the outer lock object - * @throws NullPointerException if lock null + * @throws NullPointerException if the lock is null */ protected WriteLock(ReentrantReadWriteLock lock) { sync = lock.sync; } /** - * Acquire the lock. + * Acquires the write lock. * - *

    Acquires the lock if it is not held by another thread - * and returns immediately, setting the lock hold count to + *

    Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to * one. * - *

    If the current thread already holds the lock then the + *

    If the current thread already holds the write lock then the * hold count is incremented by one and the method returns * immediately. * *

    If the lock is held by another thread then the current * thread becomes disabled for thread scheduling purposes and - * lies dormant until the lock has been acquired, at which - * time the lock hold count is set to one. + * lies dormant until the write lock has been acquired, at which + * time the write lock hold count is set to one. */ public void lock() { - sync.wlock(); + sync.acquire(1); } /** - * Acquires the lock unless the current thread is {@link - * Thread#interrupt interrupted}. + * Acquires the write lock unless the current thread is + * {@linkplain Thread#interrupt interrupted}. * - *

    Acquires the lock if it is not held by another thread - * and returns immediately, setting the lock hold count to + *

    Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately, setting the write lock hold count to * one. * *

    If the current thread already holds this lock then the @@ -653,14 +933,14 @@ * *

      * - *
    • The lock is acquired by the current thread; or + *
    • The write lock is acquired by the current thread; or * - *
    • Some other thread {@link Thread#interrupt interrupts} + *
    • Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. * *
    * - *

    If the lock is acquired by the current thread then the + *

    If the write lock is acquired by the current thread then the * lock hold count is set to one. * *

    If the current thread: @@ -670,8 +950,8 @@ *

  • has its interrupted status set on entry to this method; * or * - *
  • is {@link Thread#interrupt interrupted} while acquiring - * the lock, + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, * * * @@ -690,16 +970,17 @@ } /** - * Acquires the lock only if it is not held by another thread + * Acquires the write lock only if it is not held by another thread * at the time of invocation. * - *

    Acquires the lock if it is not held by another thread - * and returns immediately with the value true, - * setting the lock hold count to one. Even when this lock has + *

    Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. Even when this lock has * been set to use a fair ordering policy, a call to - * tryLock() will immediately acquire the + * {@code tryLock()} will immediately acquire the * lock if it is available, whether or not other threads are - * currently waiting for the lock. This "barging" + * currently waiting for the write lock. This "barging" * behavior can be useful in certain circumstances, even * though it breaks fairness. If you want to honor the * fairness setting for this lock, then use {@link @@ -708,31 +989,32 @@ * *

    If the current thread already holds this lock then the * hold count is incremented by one and the method returns - * true. + * {@code true}. * *

    If the lock is held by another thread then this method - * will return immediately with the value false. + * will return immediately with the value {@code false}. * - * @return true if the lock was free and was acquired by the - * current thread, or the lock was already held by the current thread; and - * false otherwise. + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held + * by the current thread; and {@code false} otherwise. */ public boolean tryLock( ) { - return sync.nonfairTryAcquire(1); + return sync.tryWriteLock(); } /** - * Acquires the lock if it is not held by another thread + * Acquires the write lock if it is not held by another thread * within the given waiting time and the current thread has - * not been {@link Thread#interrupt interrupted}. + * not been {@linkplain Thread#interrupt interrupted}. * - *

    Acquires the lock if it is not held by another thread - * and returns immediately with the value true, - * setting the lock hold count to one. If this lock has been + *

    Acquires the write lock if neither the read nor write lock + * are held by another thread + * and returns immediately with the value {@code true}, + * setting the write lock hold count to one. If this lock has been * set to use a fair ordering policy then an available lock * will not be acquired if any other threads are - * waiting for the lock. This is in contrast to the {@link - * #tryLock()} method. If you want a timed tryLock + * waiting for the write lock. This is in contrast to the {@link + * #tryLock()} method. If you want a timed {@code tryLock} * that does permit barging on a fair lock then combine the * timed and un-timed forms together: * @@ -741,7 +1023,7 @@ * *

    If the current thread already holds this lock then the * hold count is incremented by one and the method returns - * true. + * {@code true}. * *

    If the lock is held by another thread then the current * thread becomes disabled for thread scheduling purposes and @@ -749,17 +1031,17 @@ * *

      * - *
    • The lock is acquired by the current thread; or + *
    • The write lock is acquired by the current thread; or * - *
    • Some other thread {@link Thread#interrupt interrupts} + *
    • Some other thread {@linkplain Thread#interrupt interrupts} * the current thread; or * *
    • The specified waiting time elapses * *
    * - *

    If the lock is acquired then the value true is - * returned and the lock hold count is set to one. + *

    If the write lock is acquired then the value {@code true} is + * returned and the write lock hold count is set to one. * *

    If the current thread: * @@ -768,16 +1050,16 @@ *

  • has its interrupted status set on entry to this method; * or * - *
  • is {@link Thread#interrupt interrupted} while acquiring - * the lock, + *
  • is {@linkplain Thread#interrupt interrupted} while + * acquiring the write lock, * - * + * * * then {@link InterruptedException} is thrown and the current * thread's interrupted status is cleared. * *

    If the specified waiting time elapses then the value - * false is returned. If the time is less than or + * {@code false} is returned. If the time is less than or * equal to zero, the method will not wait at all. * *

    In this implementation, as this method is an explicit @@ -785,30 +1067,31 @@ * the interrupt over normal or reentrant acquisition of the * lock, and over reporting the elapse of the waiting time. * - * @param timeout the time to wait for the lock + * @param timeout the time to wait for the write lock * @param unit the time unit of the timeout argument * - * @return true if the lock was free and was acquired - * by the current thread, or the lock was already held by the - * current thread; and false if the waiting time + * @return {@code true} if the lock was free and was acquired + * by the current thread, or the write lock was already held by the + * current thread; and {@code false} if the waiting time * elapsed before the lock could be acquired. * * @throws InterruptedException if the current thread is interrupted - * @throws NullPointerException if unit is null + * @throws NullPointerException if the time unit is null * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } - + /** - * Attempts to release this lock. + * Attempts to release this lock. * *

    If the current thread is the holder of this lock then * the hold count is decremented. If the hold count is now * zero then the lock is released. If the current thread is * not the holder of this lock then {@link * IllegalMonitorStateException} is thrown. + * * @throws IllegalMonitorStateException if the current thread does not * hold this lock. */ @@ -818,7 +1101,7 @@ /** * Returns a {@link Condition} instance for use with this - * {@link Lock} instance. + * {@link Lock} instance. *

    The returned {@link Condition} instance supports the same * usages as do the {@link Object} monitor methods ({@link * Object#wait() wait}, {@link Object#notify notify}, and {@link @@ -834,74 +1117,80 @@ * affected. However it is essentially always an error to * invoke a condition waiting method when the current thread * has also acquired read locks, since other threads that - * could unblock it will not be able to access the write + * could unblock it will not be able to acquire the write * lock.) * - *

  • When the condition {@link Condition#await() waiting} + *
  • When the condition {@linkplain Condition#await() waiting} * methods are called the write lock is released and, before * they return, the write lock is reacquired and the lock hold * count restored to what it was when the method was called. * - *
  • If a thread is {@link Thread#interrupt interrupted} while + *
  • If a thread is {@linkplain Thread#interrupt interrupted} while * waiting then the wait will terminate, an {@link * InterruptedException} will be thrown, and the thread's * interrupted status will be cleared. * - *
  • Waiting threads are signalled in FIFO order + *
  • Waiting threads are signalled in FIFO order. * *
  • The ordering of lock reacquisition for threads returning * from waiting methods is the same as for threads initially * acquiring the lock, which is in the default case not specified, * but for fair locks favors those threads that have been * waiting the longest. - * + * * + * * @return the Condition object */ - public Condition newCondition() { + public Condition newCondition() { return sync.newCondition(); } /** * Returns a string identifying this lock, as well as its lock * state. The state, in brackets includes either the String - * "Unlocked" or the String "Locked by" - * followed by the {@link Thread#getName} of the owning thread. - * @return a string identifying this lock, as well as its lock state. + * {@code "Unlocked"} or the String {@code "Locked by"} + * followed by the {@linkplain Thread#getName name} of the owning thread. + * + * @return a string identifying this lock, as well as its lock state */ public String toString() { - Thread owner = sync.getOwner(); - return super.toString() + ((owner == null) ? + Thread o = sync.getOwner(); + return super.toString() + ((o == null) ? "[Unlocked]" : - "[Locked by thread " + owner.getName() + "]"); + "[Locked by thread " + o.getName() + "]"); } } - // Instrumentation and status /** - * Returns true if this lock has fairness set true. - * @return true if this lock has fairness set true. + * Returns {@code true} if this lock has fairness set true. + * + * @return {@code true} if this lock has fairness set true */ public final boolean isFair() { return sync instanceof FairSync; } /** - * Returns the thread that currently owns the exclusive lock, or - * null if not owned. Note that the owner may be - * momentarily null even if there are threads trying to - * acquire the lock but have not yet done so. This method is - * designed to facilitate construction of subclasses that provide - * more extensive lock monitoring facilities. - * @return the owner, or null if not owned. + * Returns the thread that currently owns the write lock, or + * {@code null} if not owned. When this method is called by a + * thread that is not the owner, the return value reflects a + * best-effort approximation of current lock status. For example, + * the owner may be momentarily {@code null} even if there are + * threads trying to acquire the lock but have not yet done so. + * This method is designed to facilitate construction of + * subclasses that provide more extensive lock monitoring + * facilities. + * + * @return the owner, or {@code null} if not owned */ protected Thread getOwner() { return sync.getOwner(); } - + /** * Queries the number of read locks held for this lock. This * method is designed for use in monitoring system state, not for @@ -916,17 +1205,19 @@ * Queries if the write lock is held by any thread. This method is * designed for use in monitoring system state, not for * synchronization control. - * @return true if any thread holds write lock and - * false otherwise. + * + * @return {@code true} if any thread holds the write lock and + * {@code false} otherwise */ public boolean isWriteLocked() { return sync.isWriteLocked(); } /** - * Queries if the write lock is held by the current thread. - * @return true if current thread holds this lock and - * false otherwise. + * Queries if the write lock is held by the current thread. + * + * @return {@code true} if the current thread holds the write lock and + * {@code false} otherwise */ public boolean isWriteLockedByCurrentThread() { return sync.isHeldExclusively(); @@ -937,8 +1228,8 @@ * current thread. A writer thread has a hold on a lock for * each lock action that is not matched by an unlock action. * - * @return the number of holds on this lock by the current thread, - * or zero if this lock is not held by the current thread. + * @return the number of holds on the write lock by the current thread, + * or zero if the write lock is not held by the current thread */ public int getWriteHoldCount() { return sync.getWriteHoldCount(); @@ -952,6 +1243,7 @@ * returned collection are in no particular order. This method is * designed to facilitate construction of subclasses that provide * more extensive lock monitoring facilities. + * * @return the collection of threads */ protected Collection getQueuedWriterThreads() { @@ -966,6 +1258,7 @@ * returned collection are in no particular order. This method is * designed to facilitate construction of subclasses that provide * more extensive lock monitoring facilities. + * * @return the collection of threads */ protected Collection getQueuedReaderThreads() { @@ -973,41 +1266,42 @@ } /** - * Queries whether any threads are waiting to acquire. Note that - * because cancellations may occur at any time, a true - * return does not guarantee that any other thread will ever - * acquire. This method is designed primarily for use in - * monitoring of the system state. + * Queries whether any threads are waiting to acquire the read or + * write lock. Note that because cancellations may occur at any + * time, a {@code true} return does not guarantee that any other + * thread will ever acquire a lock. This method is designed + * primarily for use in monitoring of the system state. * - * @return true if there may be other threads waiting to acquire - * the lock. + * @return {@code true} if there may be other threads waiting to + * acquire the lock */ - public final boolean hasQueuedThreads() { + public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** - * Queries whether the given thread is waiting to acquire this - * lock. Note that because cancellations may occur at any time, a - * true return does not guarantee that this thread - * will ever acquire. This method is designed primarily for use - * in monitoring of the system state. + * Queries whether the given thread is waiting to acquire either + * the read or write lock. Note that because cancellations may + * occur at any time, a {@code true} return does not guarantee + * that this thread will ever acquire a lock. This method is + * designed primarily for use in monitoring of the system state. * * @param thread the thread - * @return true if the given thread is queued waiting for this lock. - * @throws NullPointerException if thread is null + * @return {@code true} if the given thread is queued waiting for this lock + * @throws NullPointerException if the thread is null */ - public final boolean hasQueuedThread(Thread thread) { + public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } /** - * Returns an estimate of the number of threads waiting to - * acquire. The value is only an estimate because the number of - * threads may change dynamically while this method traverses - * internal data structures. This method is designed for use in - * monitoring of the system state, not for synchronization - * control. + * Returns an estimate of the number of threads waiting to acquire + * either the read or write lock. The value is only an estimate + * because the number of threads may change dynamically while this + * method traverses internal data structures. This method is + * designed for use in monitoring of the system state, not for + * synchronization control. + * * @return the estimated number of threads waiting for this lock */ public final int getQueueLength() { @@ -1016,12 +1310,13 @@ /** * Returns a collection containing threads that may be waiting to - * acquire. Because the actual set of threads may change - * dynamically while constructing this result, the returned - * collection is only a best-effort estimate. The elements of the - * returned collection are in no particular order. This method is - * designed to facilitate construction of subclasses that provide - * more extensive monitoring facilities. + * acquire either the read or write lock. Because the actual set + * of threads may change dynamically while constructing this + * result, the returned collection is only a best-effort estimate. + * The elements of the returned collection are in no particular + * order. This method is designed to facilitate construction of + * subclasses that provide more extensive monitoring facilities. + * * @return the collection of threads */ protected Collection getQueuedThreads() { @@ -1031,18 +1326,18 @@ /** * Queries whether any threads are waiting on the given condition * associated with the write lock. Note that because timeouts and - * interrupts may occur at any time, a true return does - * not guarantee that a future signal will awaken any + * interrupts may occur at any time, a {@code true} return does + * not guarantee that a future {@code signal} will awaken any * threads. This method is designed primarily for use in * monitoring of the system state. + * * @param condition the condition - * @return true if there are any waiting threads. - * @throws IllegalMonitorStateException if this lock - * is not held + * @return {@code true} if there are any waiting threads + * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if condition null - */ + * not associated with this lock + * @throws NullPointerException if the condition is null + */ public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); @@ -1058,14 +1353,14 @@ * serves only as an upper bound on the actual number of waiters. * This method is designed for use in monitoring of the system * state, not for synchronization control. + * * @param condition the condition - * @return the estimated number of waiting threads. - * @throws IllegalMonitorStateException if this lock - * is not held + * @return the estimated number of waiting threads + * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if condition null - */ + * not associated with this lock + * @throws NullPointerException if the condition is null + */ public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); @@ -1083,13 +1378,13 @@ * are in no particular order. This method is designed to * facilitate construction of subclasses that provide more * extensive condition monitoring facilities. + * * @param condition the condition * @return the collection of threads - * @throws IllegalMonitorStateException if this lock - * is not held + * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if condition null + * not associated with this lock + * @throws NullPointerException if the condition is null */ protected Collection getWaitingThreads(Condition condition) { if (condition == null) @@ -1101,18 +1396,19 @@ /** * Returns a string identifying this lock, as well as its lock state. - * The state, in brackets, includes the String "Write locks =" - * follwed by the number of reentrantly held write locks, and the - * String "Read locks =" followed by the number of held + * The state, in brackets, includes the String {@code "Write locks ="} + * followed by the number of reentrantly held write locks, and the + * String {@code "Read locks ="} followed by the number of held * read locks. - * @return a string identifying this lock, as well as its lock state. + * + * @return a string identifying this lock, as well as its lock state */ public String toString() { int c = sync.getCount(); - int w = exclusiveCount(c); - int r = sharedCount(c); - - return super.toString() + + int w = Sync.exclusiveCount(c); + int r = Sync.sharedCount(c); + + return super.toString() + "[Write locks = " + w + ", Read locks = " + r + "]"; } Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AbstractQueuedSynchronizerTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AbstractQueuedSynchronizerTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AbstractQueuedSynchronizerTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AbstractQueuedSynchronizerTest.java Tue Jul 28 09:30:33 2009 @@ -461,7 +461,9 @@ Thread t = new Thread(new InterruptedSyncRunnable(sync)); try { t.start(); + Thread.sleep(SHORT_DELAY_MS); t.interrupt(); + Thread.sleep(SHORT_DELAY_MS); sync.release(1); t.join(); } catch(Exception e){ @@ -950,7 +952,6 @@ sync.acquire(1); c.signal(); sync.release(1); - assert(t.isInterrupted()); t.join(SHORT_DELAY_MS); assertFalse(t.isAlive()); } Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ArrayBlockingQueueTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ArrayBlockingQueueTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ArrayBlockingQueueTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ArrayBlockingQueueTest.java Tue Jul 28 09:30:33 2009 @@ -650,6 +650,7 @@ assertEquals(SIZE, q.remainingCapacity()); q.add(one); assertFalse(q.isEmpty()); + assertTrue(q.contains(one)); q.clear(); assertTrue(q.isEmpty()); } @@ -970,6 +971,17 @@ assertEquals(l.size(), SIZE); for (int i = 0; i < SIZE; ++i) assertEquals(l.get(i), new Integer(i)); + q.add(zero); + q.add(one); + assertFalse(q.isEmpty()); + assertTrue(q.contains(zero)); + assertTrue(q.contains(one)); + l.clear(); + q.drainTo(l); + assertEquals(q.size(), 0); + assertEquals(l.size(), 2); + for (int i = 0; i < 2; ++i) + assertEquals(l.get(i), new Integer(i)); } /** @@ -1028,15 +1040,18 @@ * drainTo(c, n) empties first max {n, size} elements of queue into c */ public void testDrainToN() { + ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE*2); for (int i = 0; i < SIZE + 2; ++i) { - ArrayBlockingQueue q = populatedQueue(SIZE); + for(int j = 0; j < SIZE; j++) + assertTrue(q.offer(new Integer(j))); ArrayList l = new ArrayList(); q.drainTo(l, i); int k = (i < SIZE)? i : SIZE; - assertEquals(q.size(), SIZE-k); assertEquals(l.size(), k); + assertEquals(q.size(), SIZE-k); for (int j = 0; j < k; ++j) assertEquals(l.get(j), new Integer(j)); + while (q.poll() != null) ; } } Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerFieldUpdaterTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerFieldUpdaterTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerFieldUpdaterTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerFieldUpdaterTest.java Tue Jul 28 09:30:33 2009 @@ -60,6 +60,27 @@ catch (RuntimeException rt) {} } + static class Base { + protected volatile int f = 0; + } + static class Sub1 extends Base { + AtomicIntegerFieldUpdater fUpdater + = AtomicIntegerFieldUpdater.newUpdater(Base.class, "f"); + } + static class Sub2 extends Base {} + + public void testProtectedFieldOnAnotherSubtype() { + Sub1 sub1 = new Sub1(); + Sub2 sub2 = new Sub2(); + + sub1.fUpdater.set(sub1, 1); + try { + sub1.fUpdater.set(sub2, 2); + shouldThrow(); + } + catch (RuntimeException rt) {} + } + /** * get returns the last value set or assigned */ @@ -78,6 +99,7 @@ assertEquals(-3,a.get(this)); } + /** * compareAndSet succeeds in changing value if equal to expected else fails */ Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicIntegerTest.java Tue Jul 28 09:30:33 2009 @@ -46,6 +46,7 @@ assertEquals(-3,ai.get()); } + /** * compareAndSet succeeds in changing value if equal to expected else fails */ Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongFieldUpdaterTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongFieldUpdaterTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongFieldUpdaterTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongFieldUpdaterTest.java Tue Jul 28 09:30:33 2009 @@ -62,6 +62,27 @@ catch (RuntimeException rt) {} } + static class Base { + protected volatile long f = 0; + } + static class Sub1 extends Base { + AtomicLongFieldUpdater fUpdater + = AtomicLongFieldUpdater.newUpdater(Base.class, "f"); + } + static class Sub2 extends Base {} + + public void testProtectedFieldOnAnotherSubtype() { + Sub1 sub1 = new Sub1(); + Sub2 sub2 = new Sub2(); + + sub1.fUpdater.set(sub1, 1); + try { + sub1.fUpdater.set(sub2, 2); + shouldThrow(); + } + catch (RuntimeException rt) {} + } + /** * get returns the last value set or assigned */ @@ -78,7 +99,7 @@ assertEquals(2,a.get(this)); a.set(this,-3); assertEquals(-3,a.get(this)); - + } /** * compareAndSet succeeds in changing value if equal to expected else fails Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicLongTest.java Tue Jul 28 09:30:33 2009 @@ -46,6 +46,7 @@ assertEquals(-3,ai.get()); } + /** * compareAndSet succeeds in changing value if equal to expected else fails */ Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceFieldUpdaterTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceFieldUpdaterTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceFieldUpdaterTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceFieldUpdaterTest.java Tue Jul 28 09:30:33 2009 @@ -62,6 +62,27 @@ catch (RuntimeException rt) {} } + static class Base { + protected volatile Object f = null; + } + static class Sub1 extends Base { + AtomicReferenceFieldUpdater fUpdater + = AtomicReferenceFieldUpdater.newUpdater(Base.class, Object.class, "f"); + } + static class Sub2 extends Base {} + + public void testProtectedFieldOnAnotherSubtype() { + Sub1 sub1 = new Sub1(); + Sub2 sub2 = new Sub2(); + + sub1.fUpdater.set(sub1, "f"); + try { + sub1.fUpdater.set(sub2, "g"); + shouldThrow(); + } + catch (RuntimeException rt) {} + } + /** * get returns the last value set or assigned */ @@ -76,9 +97,8 @@ assertEquals(one,a.get(this)); a.set(this,two); assertEquals(two,a.get(this)); - a.set(this,-3); - assertEquals(-3,a.get(this).intValue()); - + a.set(this,m3); + assertEquals(m3,a.get(this)); } /** * compareAndSet succeeds in changing value if equal to expected else fails Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/AtomicReferenceTest.java Tue Jul 28 09:30:33 2009 @@ -44,7 +44,7 @@ assertEquals(two,ai.get()); ai.set(m3); assertEquals(m3,ai.get()); - + } /** * compareAndSet succeeds in changing value if equal to expected else fails Modified: harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ConcurrentHashMapTest.java URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ConcurrentHashMapTest.java?rev=798469&r1=798468&r2=798469&view=diff ============================================================================== --- harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ConcurrentHashMapTest.java (original) +++ harmony/enhanced/classlib/branches/java6/modules/concurrent/src/test/java/ConcurrentHashMapTest.java Tue Jul 28 09:30:33 2009 @@ -81,8 +81,8 @@ */ public void testContainsValue() { ConcurrentHashMap map = map5(); - assertTrue(map.contains("A")); - assertFalse(map.contains("Z")); + assertTrue(map.containsValue("A")); + assertFalse(map.containsValue("Z")); } /** @@ -150,6 +150,49 @@ } /** + * keySet.toArray returns contains all keys + */ + public void testKeySetToArray() { + ConcurrentHashMap map = map5(); + Set s = map.keySet(); + Object[] ar = s.toArray(); + assertTrue(s.containsAll(Arrays.asList(ar))); + assertEquals(5, ar.length); + ar[0] = m10; + assertFalse(s.containsAll(Arrays.asList(ar))); + } + + /** + * Values.toArray contains all values + */ + public void testValuesToArray() { + ConcurrentHashMap map = map5(); + Collection v = map.values(); + Object[] ar = v.toArray(); + ArrayList s = new ArrayList(Arrays.asList(ar)); + assertEquals(5, ar.length); + assertTrue(s.contains("A")); + assertTrue(s.contains("B")); + assertTrue(s.contains("C")); + assertTrue(s.contains("D")); + assertTrue(s.contains("E")); + } + + /** + * entrySet.toArray contains all entries + */ + public void testEntrySetToArray() { + ConcurrentHashMap map = map5(); + Set s = map.entrySet(); + Object[] ar = s.toArray(); + assertEquals(5, ar.length); + for (int i = 0; i < 5; ++i) { + assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); + assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); + } + } + + /** * values collection contains all values */ public void testValues() { @@ -501,6 +544,19 @@ } /** + * remove(x, null) returns false + */ + public void testRemove3() { + try { + ConcurrentHashMap c = new ConcurrentHashMap(5); + c.put("sadsdf", "asdads"); + assertFalse(c.remove("sadsdf", null)); + } catch(NullPointerException e){ + fail(); + } + } + + /** * A deserialized map equals original */ public void testSerialization() {