jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java
author never
Mon, 12 Jul 2010 22:27:18 -0700
changeset 5926 a36f90d986b6
parent 5506 202f599c92aa
child 7518 0282db800fe1
permissions -rw-r--r--
6968385: malformed xml in sweeper logging Reviewed-by: kvn
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2431
diff changeset
     6
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2431
diff changeset
     8
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2431
diff changeset
    20
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2431
diff changeset
    21
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2431
diff changeset
    22
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
 * This file is available under and governed by the GNU General Public
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
 * License version 2 only, as published by the Free Software Foundation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
 * However, the following notice accompanied the original version of this
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
 * file:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
 * Written by Doug Lea with assistance from members of JCP JSR-166
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
 * Expert Group and released to the public domain, as explained at
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
 * http://creativecommons.org/licenses/publicdomain
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
package java.util.concurrent.locks;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.util.concurrent.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import java.util.concurrent.atomic.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.util.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 * An implementation of {@link ReadWriteLock} supporting similar
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * semantics to {@link ReentrantLock}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * <p>This class has the following properties:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * <li><b>Acquisition order</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 * <p> This class does not impose a reader or writer preference
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 * ordering for lock access.  However, it does support an optional
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 * <em>fairness</em> policy.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 * <dl>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 * <dt><b><i>Non-fair mode (default)</i></b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 * <dd>When constructed as non-fair (the default), the order of entry
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
 * to the read and write lock is unspecified, subject to reentrancy
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
 * constraints.  A nonfair lock that is continuously contended may
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
 * indefinitely postpone one or more reader or writer threads, but
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
 * will normally have higher throughput than a fair lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
 * <p>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
 * <dt><b><i>Fair mode</i></b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
 * <dd> When constructed as fair, threads contend for entry using an
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
 * approximately arrival-order policy. When the currently held lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
 * is released either the longest-waiting single writer thread will
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
 * be assigned the write lock, or if there is a group of reader threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
 * waiting longer than all waiting writer threads, that group will be
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
 * assigned the read lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
 * <p>A thread that tries to acquire a fair read lock (non-reentrantly)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
 * will block if either the write lock is held, or there is a waiting
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
 * writer thread. The thread will not acquire the read lock until
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
 * after the oldest currently waiting writer thread has acquired and
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
 * released the write lock. Of course, if a waiting writer abandons
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
 * its wait, leaving one or more reader threads as the longest waiters
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
 * in the queue with the write lock free, then those readers will be
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
 * assigned the read lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
 * <p>A thread that tries to acquire a fair write lock (non-reentrantly)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
 * will block unless both the read lock and write lock are free (which
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
 * implies there are no waiting threads).  (Note that the non-blocking
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
 * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
 * do not honor this fair setting and will acquire the lock if it is
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
 * possible, regardless of waiting threads.)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
 * <p>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
 * </dl>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
 * <li><b>Reentrancy</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
 * <p>This lock allows both readers and writers to reacquire read or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
 * write locks in the style of a {@link ReentrantLock}. Non-reentrant
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
 * readers are not allowed until all write locks held by the writing
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
 * thread have been released.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
 * <p>Additionally, a writer can acquire the read lock, but not
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
 * vice-versa.  Among other applications, reentrancy can be useful
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
 * when write locks are held during calls or callbacks to methods that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
 * perform reads under read locks.  If a reader tries to acquire the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
 * write lock it will never succeed.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
 * <li><b>Lock downgrading</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
 * <p>Reentrancy also allows downgrading from the write lock to a read lock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
 * by acquiring the write lock, then the read lock and then releasing the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
 * write lock. However, upgrading from a read lock to the write lock is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
 * <b>not</b> possible.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
 * <li><b>Interruption of lock acquisition</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
 * <p>The read lock and write lock both support interruption during lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
 * acquisition.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
 * <li><b>{@link Condition} support</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
 * <p>The write lock provides a {@link Condition} implementation that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
 * behaves in the same way, with respect to the write lock, as the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
 * {@link Condition} implementation provided by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
 * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
 * This {@link Condition} can, of course, only be used with the write lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
 * <p>The read lock does not support a {@link Condition} and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
 * {@code readLock().newCondition()} throws
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
 * {@code UnsupportedOperationException}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
 * <li><b>Instrumentation</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
 * <p>This class supports methods to determine whether locks
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
 * are held or contended. These methods are designed for monitoring
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
 * system state, not for synchronization control.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
 * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
 * <p>Serialization of this class behaves in the same way as built-in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
 * locks: a deserialized lock is in the unlocked state, regardless of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
 * its state when serialized.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
 * <p><b>Sample usages</b>. Here is a code sketch showing how to perform
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
 * lock downgrading after updating a cache (exception handling is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
 * particularly tricky when handling multiple locks in a non-nested
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
 * fashion):
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
 * <pre> {@code
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
 * class CachedData {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
 *   Object data;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
 *   volatile boolean cacheValid;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
 *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
 *   void processCachedData() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
 *     rwl.readLock().lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
 *     if (!cacheValid) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
 *        // Must release read lock before acquiring write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
 *        rwl.readLock().unlock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
 *        rwl.writeLock().lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
 *        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
 *          // Recheck state because another thread might have
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
 *          // acquired write lock and changed state before we did.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
 *          if (!cacheValid) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
 *            data = ...
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
 *            cacheValid = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
 *          }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
 *          // Downgrade by acquiring read lock before releasing write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
 *          rwl.readLock().lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
 *        } finally  {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
 *          rwl.writeLock().unlock(); // Unlock write, still hold read
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
 *        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
 *     }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
 *     try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
 *       use(data);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
 *     } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
 *       rwl.readLock().unlock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
 *     }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
 *   }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
 * }}</pre>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
 * ReentrantReadWriteLocks can be used to improve concurrency in some
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
 * uses of some kinds of Collections. This is typically worthwhile
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
 * only when the collections are expected to be large, accessed by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
 * more reader threads than writer threads, and entail operations with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
 * overhead that outweighs synchronization overhead. For example, here
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
 * is a class using a TreeMap that is expected to be large and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
 * concurrently accessed.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
 * <pre>{@code
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
 * class RWDictionary {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
 *    private final Map<String, Data> m = new TreeMap<String, Data>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
 *    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
 *    private final Lock r = rwl.readLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
 *    private final Lock w = rwl.writeLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
 *    public Data get(String key) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
 *        r.lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
 *        try { return m.get(key); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
 *        finally { r.unlock(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
 *    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
 *    public String[] allKeys() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
 *        r.lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
 *        try { return m.keySet().toArray(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
 *        finally { r.unlock(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
 *    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
 *    public Data put(String key, Data value) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
 *        w.lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
 *        try { return m.put(key, value); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
 *        finally { w.unlock(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
 *    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
 *    public void clear() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
 *        w.lock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
 *        try { m.clear(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
 *        finally { w.unlock(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
 *    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
 * }}</pre>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
 * <h3>Implementation Notes</h3>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
 * <p>This lock supports a maximum of 65535 recursive write locks
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
 * and 65535 read locks. Attempts to exceed these limits result in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
 * {@link Error} throws from locking methods.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
 * @since 1.5
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
 * @author Doug Lea
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable  {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
    private static final long serialVersionUID = -6992448646407690164L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
    /** Inner class providing readlock */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
    private final ReentrantReadWriteLock.ReadLock readerLock;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
    /** Inner class providing writelock */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
    private final ReentrantReadWriteLock.WriteLock writerLock;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
    /** Performs all synchronization mechanics */
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   225
    final Sync sync;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
     * Creates a new {@code ReentrantReadWriteLock} with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
     * default (nonfair) ordering properties.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
    public ReentrantReadWriteLock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
        this(false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
     * Creates a new {@code ReentrantReadWriteLock} with
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
     * the given fairness policy.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
     * @param fair {@code true} if this lock should use a fair ordering policy
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
    public ReentrantReadWriteLock(boolean fair) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   242
        sync = fair ? new FairSync() : new NonfairSync();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
        readerLock = new ReadLock(this);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
        writerLock = new WriteLock(this);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
     * Synchronization implementation for ReentrantReadWriteLock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
     * Subclassed into fair and nonfair versions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
    static abstract class Sync extends AbstractQueuedSynchronizer {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
        private static final long serialVersionUID = 6317671515068378041L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
         * Read vs write count extraction constants and functions.
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   259
         * Lock state is logically divided into two unsigned shorts:
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   260
         * The lower one representing the exclusive (writer) lock hold count,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
         * and the upper the shared (reader) hold count.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
        static final int SHARED_SHIFT   = 16;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
        /** Returns the number of shared holds represented in count  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
        /** Returns the number of exclusive holds represented in count  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
         * A counter for per-thread read hold counts.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
         * Maintained as a ThreadLocal; cached in cachedHoldCounter
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
        static final class HoldCounter {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   279
            int count = 0;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
            // Use id, not reference, to avoid garbage retention
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
            final long tid = Thread.currentThread().getId();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
         * ThreadLocal subclass. Easiest to explicitly define for sake
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
         * of deserialization mechanics.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
        static final class ThreadLocalHoldCounter
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            extends ThreadLocal<HoldCounter> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
            public HoldCounter initialValue() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
                return new HoldCounter();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
        /**
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   296
         * The number of reentrant read locks held by current thread.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
         * Initialized only in constructor and readObject.
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   298
         * Removed whenever a thread's read hold count drops to 0.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
         */
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   300
        private transient ThreadLocalHoldCounter readHolds;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
         * The hold count of the last thread to successfully acquire
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
         * readLock. This saves ThreadLocal lookup in the common case
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
         * where the next thread to release is the last one to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
         * acquire. This is non-volatile since it is just used
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
         * as a heuristic, and would be great for threads to cache.
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   308
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   309
         * <p>Can outlive the Thread for which it is caching the read
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   310
         * hold count, but avoids garbage retention by not retaining a
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   311
         * reference to the Thread.
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   312
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   313
         * <p>Accessed via a benign data race; relies on the memory
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   314
         * model's final field and out-of-thin-air guarantees.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
         */
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   316
        private transient HoldCounter cachedHoldCounter;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   317
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   318
        /**
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   319
         * firstReader is the first thread to have acquired the read lock.
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   320
         * firstReaderHoldCount is firstReader's hold count.
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   321
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   322
         * <p>More precisely, firstReader is the unique thread that last
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   323
         * changed the shared count from 0 to 1, and has not released the
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   324
         * read lock since then; null if there is no such thread.
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   325
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   326
         * <p>Cannot cause garbage retention unless the thread terminated
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   327
         * without relinquishing its read locks, since tryReleaseShared
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   328
         * sets it to null.
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   329
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   330
         * <p>Accessed via a benign data race; relies on the memory
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   331
         * model's out-of-thin-air guarantees for references.
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   332
         *
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   333
         * <p>This allows tracking of read holds for uncontended read
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   334
         * locks to be very cheap.
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   335
         */
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   336
        private transient Thread firstReader = null;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   337
        private transient int firstReaderHoldCount;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
        Sync() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
            readHolds = new ThreadLocalHoldCounter();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
            setState(getState()); // ensures visibility of readHolds
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
         * Acquires and releases use the same code for fair and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
         * nonfair locks, but differ in whether/how they allow barging
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
         * when queues are non-empty.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
         * Returns true if the current thread, when trying to acquire
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
         * the read lock, and otherwise eligible to do so, should block
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
         * because of policy for overtaking other waiting threads.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
        abstract boolean readerShouldBlock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
         * Returns true if the current thread, when trying to acquire
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
         * the write lock, and otherwise eligible to do so, should block
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
         * because of policy for overtaking other waiting threads.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
        abstract boolean writerShouldBlock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
        /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
         * Note that tryRelease and tryAcquire can be called by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
         * Conditions. So it is possible that their arguments contain
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
         * both read and write holds that are all released during a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
         * condition wait and re-established in tryAcquire.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
        protected final boolean tryRelease(int releases) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
            if (!isHeldExclusively())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
                throw new IllegalMonitorStateException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
            int nextc = getState() - releases;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
            boolean free = exclusiveCount(nextc) == 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
            if (free)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
                setExclusiveOwnerThread(null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
            setState(nextc);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
            return free;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
        protected final boolean tryAcquire(int acquires) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
             * Walkthrough:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
             * 1. If read count nonzero or write count nonzero
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
             *    and owner is a different thread, fail.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
             * 2. If count would saturate, fail. (This can only
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
             *    happen if count is already nonzero.)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
             * 3. Otherwise, this thread is eligible for lock if
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
             *    it is either a reentrant acquire or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
             *    queue policy allows it. If so, update state
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
             *    and set owner.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
            Thread current = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
            int c = getState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
            int w = exclusiveCount(c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
            if (c != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
                // (Note: if c != 0 and w == 0 then shared count != 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
                if (w == 0 || current != getExclusiveOwnerThread())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
                    return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
                if (w + exclusiveCount(acquires) > MAX_COUNT)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
                    throw new Error("Maximum lock count exceeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
                // Reentrant acquire
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
                setState(c + acquires);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
                return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
            if (writerShouldBlock() ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
                !compareAndSetState(c, c + acquires))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
            setExclusiveOwnerThread(current);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
        protected final boolean tryReleaseShared(int unused) {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   415
            Thread current = Thread.currentThread();
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   416
            if (firstReader == current) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   417
                // assert firstReaderHoldCount > 0;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   418
                if (firstReaderHoldCount == 1)
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   419
                    firstReader = null;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   420
                else
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   421
                    firstReaderHoldCount--;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   422
            } else {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   423
                HoldCounter rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   424
                if (rh == null || rh.tid != current.getId())
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   425
                    rh = readHolds.get();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   426
                int count = rh.count;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   427
                if (count <= 1) {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   428
                    readHolds.remove();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   429
                    if (count <= 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   430
                        throw unmatchedUnlockException();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   431
                }
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   432
                --rh.count;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   433
            }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
            for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
                int c = getState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
                int nextc = c - SHARED_UNIT;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
                if (compareAndSetState(c, nextc))
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   438
                    // Releasing the read lock has no effect on readers,
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   439
                    // but it may allow waiting writers to proceed if
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   440
                    // both read and write locks are now free.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
                    return nextc == 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   445
        private IllegalMonitorStateException unmatchedUnlockException() {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   446
            return new IllegalMonitorStateException(
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   447
                "attempt to unlock read lock, not locked by current thread");
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   448
        }
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   449
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
        protected final int tryAcquireShared(int unused) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
             * Walkthrough:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
             * 1. If write lock held by another thread, fail.
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   454
             * 2. Otherwise, this thread is eligible for
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
             *    lock wrt state, so ask if it should block
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
             *    because of queue policy. If not, try
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
             *    to grant by CASing state and updating count.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
             *    Note that step does not check for reentrant
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
             *    acquires, which is postponed to full version
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
             *    to avoid having to check hold count in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
             *    the more typical non-reentrant case.
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   462
             * 3. If step 2 fails either because thread
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   463
             *    apparently not eligible or CAS fails or count
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   464
             *    saturated, chain to version with full retry loop.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
            Thread current = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
            int c = getState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
            if (exclusiveCount(c) != 0 &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
                getExclusiveOwnerThread() != current)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
                return -1;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   471
            int r = sharedCount(c);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
            if (!readerShouldBlock() &&
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   473
                r < MAX_COUNT &&
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
                compareAndSetState(c, c + SHARED_UNIT)) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   475
                if (r == 0) {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   476
                    firstReader = current;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   477
                    firstReaderHoldCount = 1;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   478
                } else if (firstReader == current) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   479
                    firstReaderHoldCount++;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   480
                } else {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   481
                    HoldCounter rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   482
                    if (rh == null || rh.tid != current.getId())
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   483
                        cachedHoldCounter = rh = readHolds.get();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   484
                    else if (rh.count == 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   485
                        readHolds.set(rh);
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   486
                    rh.count++;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   487
                }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
                return 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
            return fullTryAcquireShared(current);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
         * Full version of acquire for reads, that handles CAS misses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
         * and reentrant reads not dealt with in tryAcquireShared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
        final int fullTryAcquireShared(Thread current) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
            /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
             * This code is in part redundant with that in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
             * tryAcquireShared but is simpler overall by not
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
             * complicating tryAcquireShared with interactions between
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
             * retries and lazily reading hold counts.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
             */
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   504
            HoldCounter rh = null;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
            for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
                int c = getState();
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   507
                if (exclusiveCount(c) != 0) {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   508
                    if (getExclusiveOwnerThread() != current)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   509
                        return -1;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   510
                    // else we hold the exclusive lock; blocking here
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   511
                    // would cause deadlock.
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   512
                } else if (readerShouldBlock()) {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   513
                    // Make sure we're not acquiring read lock reentrantly
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   514
                    if (firstReader == current) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   515
                        // assert firstReaderHoldCount > 0;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   516
                    } else {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   517
                        if (rh == null) {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   518
                            rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   519
                            if (rh == null || rh.tid != current.getId()) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   520
                                rh = readHolds.get();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   521
                                if (rh.count == 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   522
                                    readHolds.remove();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   523
                            }
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   524
                        }
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   525
                        if (rh.count == 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   526
                            return -1;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   527
                    }
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   528
                }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
                if (sharedCount(c) == MAX_COUNT)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
                    throw new Error("Maximum lock count exceeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
                if (compareAndSetState(c, c + SHARED_UNIT)) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   532
                    if (sharedCount(c) == 0) {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   533
                        firstReader = current;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   534
                        firstReaderHoldCount = 1;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   535
                    } else if (firstReader == current) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   536
                        firstReaderHoldCount++;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   537
                    } else {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   538
                        if (rh == null)
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   539
                            rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   540
                        if (rh == null || rh.tid != current.getId())
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   541
                            rh = readHolds.get();
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   542
                        else if (rh.count == 0)
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   543
                            readHolds.set(rh);
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   544
                        rh.count++;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   545
                        cachedHoldCounter = rh; // cache for release
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   546
                    }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
                    return 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
         * Performs tryLock for write, enabling barging in both modes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
         * This is identical in effect to tryAcquire except for lack
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   555
         * of calls to writerShouldBlock.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
        final boolean tryWriteLock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
            Thread current = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
            int c = getState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
            if (c != 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
                int w = exclusiveCount(c);
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   562
                if (w == 0 || current != getExclusiveOwnerThread())
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
                    return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
                if (w == MAX_COUNT)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   565
                    throw new Error("Maximum lock count exceeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
            if (!compareAndSetState(c, c + 1))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
            setExclusiveOwnerThread(current);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
         * Performs tryLock for read, enabling barging in both modes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
         * This is identical in effect to tryAcquireShared except for
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   576
         * lack of calls to readerShouldBlock.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
        final boolean tryReadLock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
            Thread current = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
            for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
                int c = getState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
                if (exclusiveCount(c) != 0 &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
                    getExclusiveOwnerThread() != current)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
                    return false;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   585
                int r = sharedCount(c);
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   586
                if (r == MAX_COUNT)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
                    throw new Error("Maximum lock count exceeded");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
                if (compareAndSetState(c, c + SHARED_UNIT)) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   589
                    if (r == 0) {
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   590
                        firstReader = current;
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   591
                        firstReaderHoldCount = 1;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   592
                    } else if (firstReader == current) {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   593
                        firstReaderHoldCount++;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   594
                    } else {
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   595
                        HoldCounter rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   596
                        if (rh == null || rh.tid != current.getId())
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   597
                            cachedHoldCounter = rh = readHolds.get();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   598
                        else if (rh.count == 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   599
                            readHolds.set(rh);
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   600
                        rh.count++;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   601
                    }
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
                    return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
        protected final boolean isHeldExclusively() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
            // While we must in general read state before owner,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
            // we don't need to do so to check if current thread is owner
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
            return getExclusiveOwnerThread() == Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
        // Methods relayed to outer class
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
        final ConditionObject newCondition() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
            return new ConditionObject();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
        final Thread getOwner() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   620
            // Must read state before owner to ensure memory consistency
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
            return ((exclusiveCount(getState()) == 0)?
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
                    null :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   623
                    getExclusiveOwnerThread());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   625
90ce3da70b43 Initial load
duke
parents:
diff changeset
   626
        final int getReadLockCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   627
            return sharedCount(getState());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   628
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
        final boolean isWriteLocked() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   631
            return exclusiveCount(getState()) != 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
        final int getWriteHoldCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   635
            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   636
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
        final int getReadHoldCount() {
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   639
            if (getReadLockCount() == 0)
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   640
                return 0;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   641
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   642
            Thread current = Thread.currentThread();
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   643
            if (firstReader == current)
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   644
                return firstReaderHoldCount;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   645
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   646
            HoldCounter rh = cachedHoldCounter;
2431
54a65419300f 6822903: Reliability and documentation improvements for ReentrantReadWriteLock
dl
parents: 62
diff changeset
   647
            if (rh != null && rh.tid == current.getId())
62
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   648
                return rh.count;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   649
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   650
            int count = readHolds.get().count;
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   651
            if (count == 0) readHolds.remove();
ea448c54b34b 6625723: Excessive ThreadLocal storage used by ReentrantReadWriteLock
martin
parents: 2
diff changeset
   652
            return count;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   653
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   654
90ce3da70b43 Initial load
duke
parents:
diff changeset
   655
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   656
         * Reconstitute this lock instance from a stream
90ce3da70b43 Initial load
duke
parents:
diff changeset
   657
         * @param s the stream
90ce3da70b43 Initial load
duke
parents:
diff changeset
   658
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   659
        private void readObject(java.io.ObjectInputStream s)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   660
            throws java.io.IOException, ClassNotFoundException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   661
            s.defaultReadObject();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   662
            readHolds = new ThreadLocalHoldCounter();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   663
            setState(0); // reset to unlocked state
90ce3da70b43 Initial load
duke
parents:
diff changeset
   664
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   665
90ce3da70b43 Initial load
duke
parents:
diff changeset
   666
        final int getCount() { return getState(); }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   667
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   668
90ce3da70b43 Initial load
duke
parents:
diff changeset
   669
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   670
     * Nonfair version of Sync
90ce3da70b43 Initial load
duke
parents:
diff changeset
   671
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   672
    final static class NonfairSync extends Sync {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   673
        private static final long serialVersionUID = -8159625535654395037L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   674
        final boolean writerShouldBlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   675
            return false; // writers can always barge
90ce3da70b43 Initial load
duke
parents:
diff changeset
   676
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   677
        final boolean readerShouldBlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   678
            /* As a heuristic to avoid indefinite writer starvation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   679
             * block if the thread that momentarily appears to be head
90ce3da70b43 Initial load
duke
parents:
diff changeset
   680
             * of queue, if one exists, is a waiting writer.  This is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   681
             * only a probabilistic effect since a new reader will not
90ce3da70b43 Initial load
duke
parents:
diff changeset
   682
             * block if there is a waiting writer behind other enabled
90ce3da70b43 Initial load
duke
parents:
diff changeset
   683
             * readers that have not yet drained from the queue.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   684
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   685
            return apparentlyFirstQueuedIsExclusive();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   686
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   687
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   688
90ce3da70b43 Initial load
duke
parents:
diff changeset
   689
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   690
     * Fair version of Sync
90ce3da70b43 Initial load
duke
parents:
diff changeset
   691
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   692
    final static class FairSync extends Sync {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   693
        private static final long serialVersionUID = -2274990926593161451L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   694
        final boolean writerShouldBlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   695
            return hasQueuedPredecessors();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   696
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   697
        final boolean readerShouldBlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   698
            return hasQueuedPredecessors();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   699
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   700
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   701
90ce3da70b43 Initial load
duke
parents:
diff changeset
   702
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   703
     * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   704
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   705
    public static class ReadLock implements Lock, java.io.Serializable  {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   706
        private static final long serialVersionUID = -5992448646407690164L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   707
        private final Sync sync;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   708
90ce3da70b43 Initial load
duke
parents:
diff changeset
   709
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   710
         * Constructor for use by subclasses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   711
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   712
         * @param lock the outer lock object
90ce3da70b43 Initial load
duke
parents:
diff changeset
   713
         * @throws NullPointerException if the lock is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
   714
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   715
        protected ReadLock(ReentrantReadWriteLock lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   716
            sync = lock.sync;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   717
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   718
90ce3da70b43 Initial load
duke
parents:
diff changeset
   719
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   720
         * Acquires the read lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   721
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   722
         * <p>Acquires the read lock if the write lock is not held by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   723
         * another thread and returns immediately.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   724
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   725
         * <p>If the write lock is held by another thread then
90ce3da70b43 Initial load
duke
parents:
diff changeset
   726
         * the current thread becomes disabled for thread scheduling
90ce3da70b43 Initial load
duke
parents:
diff changeset
   727
         * purposes and lies dormant until the read lock has been acquired.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   728
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   729
        public void lock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   730
            sync.acquireShared(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   731
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   732
90ce3da70b43 Initial load
duke
parents:
diff changeset
   733
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   734
         * Acquires the read lock unless the current thread is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   735
         * {@linkplain Thread#interrupt interrupted}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   736
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   737
         * <p>Acquires the read lock if the write lock is not held
90ce3da70b43 Initial load
duke
parents:
diff changeset
   738
         * by another thread and returns immediately.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   739
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   740
         * <p>If the write lock is held by another thread then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   741
         * current thread becomes disabled for thread scheduling
90ce3da70b43 Initial load
duke
parents:
diff changeset
   742
         * purposes and lies dormant until one of two things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   743
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   744
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   745
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   746
         * <li>The read lock is acquired by the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   747
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   748
         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   749
         * the current thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   750
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   751
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   752
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   753
         * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   754
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   755
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   756
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   757
         * <li>has its interrupted status set on entry to this method; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   758
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   759
         * <li>is {@linkplain Thread#interrupt interrupted} while
90ce3da70b43 Initial load
duke
parents:
diff changeset
   760
         * acquiring the read lock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   761
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   762
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   763
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   764
         * then {@link InterruptedException} is thrown and the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
   765
         * thread's interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   766
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   767
         * <p>In this implementation, as this method is an explicit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   768
         * interruption point, preference is given to responding to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   769
         * the interrupt over normal or reentrant acquisition of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   770
         * lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   771
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   772
         * @throws InterruptedException if the current thread is interrupted
90ce3da70b43 Initial load
duke
parents:
diff changeset
   773
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   774
        public void lockInterruptibly() throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   775
            sync.acquireSharedInterruptibly(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   776
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   777
90ce3da70b43 Initial load
duke
parents:
diff changeset
   778
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   779
         * Acquires the read lock only if the write lock is not held by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   780
         * another thread at the time of invocation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   781
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   782
         * <p>Acquires the read lock if the write lock is not held by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   783
         * another thread and returns immediately with the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   784
         * {@code true}. Even when this lock has been set to use a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   785
         * fair ordering policy, a call to {@code tryLock()}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   786
         * <em>will</em> immediately acquire the read lock if it is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   787
         * available, whether or not other threads are currently
90ce3da70b43 Initial load
duke
parents:
diff changeset
   788
         * waiting for the read lock.  This &quot;barging&quot; behavior
90ce3da70b43 Initial load
duke
parents:
diff changeset
   789
         * can be useful in certain circumstances, even though it
90ce3da70b43 Initial load
duke
parents:
diff changeset
   790
         * breaks fairness. If you want to honor the fairness setting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   791
         * for this lock, then use {@link #tryLock(long, TimeUnit)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   792
         * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent
90ce3da70b43 Initial load
duke
parents:
diff changeset
   793
         * (it also detects interruption).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   794
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   795
         * <p>If the write lock is held by another thread then
90ce3da70b43 Initial load
duke
parents:
diff changeset
   796
         * this method will return immediately with the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   797
         * {@code false}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   798
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   799
         * @return {@code true} if the read lock was acquired
90ce3da70b43 Initial load
duke
parents:
diff changeset
   800
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   801
        public  boolean tryLock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   802
            return sync.tryReadLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   803
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   804
90ce3da70b43 Initial load
duke
parents:
diff changeset
   805
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   806
         * Acquires the read lock if the write lock is not held by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   807
         * another thread within the given waiting time and the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   808
         * current thread has not been {@linkplain Thread#interrupt
90ce3da70b43 Initial load
duke
parents:
diff changeset
   809
         * interrupted}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   810
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   811
         * <p>Acquires the read lock if the write lock is not held by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   812
         * another thread and returns immediately with the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   813
         * {@code true}. If this lock has been set to use a fair
90ce3da70b43 Initial load
duke
parents:
diff changeset
   814
         * ordering policy then an available lock <em>will not</em> be
90ce3da70b43 Initial load
duke
parents:
diff changeset
   815
         * acquired if any other threads are waiting for the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   816
         * lock. This is in contrast to the {@link #tryLock()}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   817
         * method. If you want a timed {@code tryLock} that does
90ce3da70b43 Initial load
duke
parents:
diff changeset
   818
         * permit barging on a fair lock then combine the timed and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   819
         * un-timed forms together:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   820
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   821
         * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   822
         * </pre>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   823
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   824
         * <p>If the write lock is held by another thread then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   825
         * current thread becomes disabled for thread scheduling
90ce3da70b43 Initial load
duke
parents:
diff changeset
   826
         * purposes and lies dormant until one of three things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   827
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   828
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   829
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   830
         * <li>The read lock is acquired by the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   831
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   832
         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   833
         * the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   834
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   835
         * <li>The specified waiting time elapses.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   836
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   837
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   838
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   839
         * <p>If the read lock is acquired then the value {@code true} is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   840
         * returned.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   841
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   842
         * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   843
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   844
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   845
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   846
         * <li>has its interrupted status set on entry to this method; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   847
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   848
         * <li>is {@linkplain Thread#interrupt interrupted} while
90ce3da70b43 Initial load
duke
parents:
diff changeset
   849
         * acquiring the read lock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   850
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   851
         * </ul> then {@link InterruptedException} is thrown and the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   852
         * current thread's interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   853
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   854
         * <p>If the specified waiting time elapses then the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   855
         * {@code false} is returned.  If the time is less than or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   856
         * equal to zero, the method will not wait at all.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   857
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   858
         * <p>In this implementation, as this method is an explicit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   859
         * interruption point, preference is given to responding to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   860
         * the interrupt over normal or reentrant acquisition of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   861
         * lock, and over reporting the elapse of the waiting time.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   862
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   863
         * @param timeout the time to wait for the read lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   864
         * @param unit the time unit of the timeout argument
90ce3da70b43 Initial load
duke
parents:
diff changeset
   865
         * @return {@code true} if the read lock was acquired
90ce3da70b43 Initial load
duke
parents:
diff changeset
   866
         * @throws InterruptedException if the current thread is interrupted
90ce3da70b43 Initial load
duke
parents:
diff changeset
   867
         * @throws NullPointerException if the time unit is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
   868
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   869
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   870
        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   871
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   872
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   873
90ce3da70b43 Initial load
duke
parents:
diff changeset
   874
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   875
         * Attempts to release this lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   876
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   877
         * <p> If the number of readers is now zero then the lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   878
         * is made available for write lock attempts.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   879
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   880
        public  void unlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   881
            sync.releaseShared(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   882
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   883
90ce3da70b43 Initial load
duke
parents:
diff changeset
   884
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   885
         * Throws {@code UnsupportedOperationException} because
90ce3da70b43 Initial load
duke
parents:
diff changeset
   886
         * {@code ReadLocks} do not support conditions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   887
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   888
         * @throws UnsupportedOperationException always
90ce3da70b43 Initial load
duke
parents:
diff changeset
   889
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   890
        public Condition newCondition() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   891
            throw new UnsupportedOperationException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   892
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   893
90ce3da70b43 Initial load
duke
parents:
diff changeset
   894
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   895
         * Returns a string identifying this lock, as well as its lock state.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   896
         * The state, in brackets, includes the String {@code "Read locks ="}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   897
         * followed by the number of held read locks.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   898
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   899
         * @return a string identifying this lock, as well as its lock state
90ce3da70b43 Initial load
duke
parents:
diff changeset
   900
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   901
        public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   902
            int r = sync.getReadLockCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   903
            return super.toString() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   904
                "[Read locks = " + r + "]";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   905
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   906
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   907
90ce3da70b43 Initial load
duke
parents:
diff changeset
   908
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   909
     * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   910
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   911
    public static class WriteLock implements Lock, java.io.Serializable  {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   912
        private static final long serialVersionUID = -4992448646407690164L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   913
        private final Sync sync;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   914
90ce3da70b43 Initial load
duke
parents:
diff changeset
   915
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   916
         * Constructor for use by subclasses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   917
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   918
         * @param lock the outer lock object
90ce3da70b43 Initial load
duke
parents:
diff changeset
   919
         * @throws NullPointerException if the lock is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
   920
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   921
        protected WriteLock(ReentrantReadWriteLock lock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   922
            sync = lock.sync;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   923
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   924
90ce3da70b43 Initial load
duke
parents:
diff changeset
   925
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   926
         * Acquires the write lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   927
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   928
         * <p>Acquires the write lock if neither the read nor write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   929
         * are held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   930
         * and returns immediately, setting the write lock hold count to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   931
         * one.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   932
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   933
         * <p>If the current thread already holds the write lock then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   934
         * hold count is incremented by one and the method returns
90ce3da70b43 Initial load
duke
parents:
diff changeset
   935
         * immediately.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   936
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   937
         * <p>If the lock is held by another thread then the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
   938
         * thread becomes disabled for thread scheduling purposes and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   939
         * lies dormant until the write lock has been acquired, at which
90ce3da70b43 Initial load
duke
parents:
diff changeset
   940
         * time the write lock hold count is set to one.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   941
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   942
        public void lock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   943
            sync.acquire(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   944
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   945
90ce3da70b43 Initial load
duke
parents:
diff changeset
   946
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   947
         * Acquires the write lock unless the current thread is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   948
         * {@linkplain Thread#interrupt interrupted}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   949
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   950
         * <p>Acquires the write lock if neither the read nor write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
   951
         * are held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   952
         * and returns immediately, setting the write lock hold count to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   953
         * one.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   954
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   955
         * <p>If the current thread already holds this lock then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   956
         * hold count is incremented by one and the method returns
90ce3da70b43 Initial load
duke
parents:
diff changeset
   957
         * immediately.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   958
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   959
         * <p>If the lock is held by another thread then the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
   960
         * thread becomes disabled for thread scheduling purposes and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   961
         * lies dormant until one of two things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   962
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   963
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   964
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   965
         * <li>The write lock is acquired by the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   966
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   967
         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   968
         * the current thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   969
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   970
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   971
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   972
         * <p>If the write lock is acquired by the current thread then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   973
         * lock hold count is set to one.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   974
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   975
         * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   976
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   977
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   978
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   979
         * <li>has its interrupted status set on entry to this method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   980
         * or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   981
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   982
         * <li>is {@linkplain Thread#interrupt interrupted} while
90ce3da70b43 Initial load
duke
parents:
diff changeset
   983
         * acquiring the write lock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   984
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   985
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   986
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   987
         * then {@link InterruptedException} is thrown and the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
   988
         * thread's interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   989
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   990
         * <p>In this implementation, as this method is an explicit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   991
         * interruption point, preference is given to responding to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   992
         * the interrupt over normal or reentrant acquisition of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   993
         * lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   994
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   995
         * @throws InterruptedException if the current thread is interrupted
90ce3da70b43 Initial load
duke
parents:
diff changeset
   996
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   997
        public void lockInterruptibly() throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   998
            sync.acquireInterruptibly(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   999
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1000
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1001
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1002
         * Acquires the write lock only if it is not held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1003
         * at the time of invocation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1004
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1005
         * <p>Acquires the write lock if neither the read nor write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1006
         * are held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1007
         * and returns immediately with the value {@code true},
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1008
         * setting the write lock hold count to one. Even when this lock has
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1009
         * been set to use a fair ordering policy, a call to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1010
         * {@code tryLock()} <em>will</em> immediately acquire the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1011
         * lock if it is available, whether or not other threads are
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1012
         * currently waiting for the write lock.  This &quot;barging&quot;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1013
         * behavior can be useful in certain circumstances, even
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1014
         * though it breaks fairness. If you want to honor the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1015
         * fairness setting for this lock, then use {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1016
         * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1017
         * which is almost equivalent (it also detects interruption).
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1018
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1019
         * <p> If the current thread already holds this lock then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1020
         * hold count is incremented by one and the method returns
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1021
         * {@code true}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1022
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1023
         * <p>If the lock is held by another thread then this method
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1024
         * will return immediately with the value {@code false}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1025
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1026
         * @return {@code true} if the lock was free and was acquired
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1027
         * by the current thread, or the write lock was already held
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1028
         * by the current thread; and {@code false} otherwise.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1029
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1030
        public boolean tryLock( ) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1031
            return sync.tryWriteLock();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1032
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1033
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1034
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1035
         * Acquires the write lock if it is not held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1036
         * within the given waiting time and the current thread has
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1037
         * not been {@linkplain Thread#interrupt interrupted}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1038
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1039
         * <p>Acquires the write lock if neither the read nor write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1040
         * are held by another thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1041
         * and returns immediately with the value {@code true},
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1042
         * setting the write lock hold count to one. If this lock has been
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1043
         * set to use a fair ordering policy then an available lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1044
         * <em>will not</em> be acquired if any other threads are
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1045
         * waiting for the write lock. This is in contrast to the {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1046
         * #tryLock()} method. If you want a timed {@code tryLock}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1047
         * that does permit barging on a fair lock then combine the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1048
         * timed and un-timed forms together:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1049
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1050
         * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1051
         * </pre>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1052
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1053
         * <p>If the current thread already holds this lock then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1054
         * hold count is incremented by one and the method returns
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1055
         * {@code true}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1056
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1057
         * <p>If the lock is held by another thread then the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1058
         * thread becomes disabled for thread scheduling purposes and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1059
         * lies dormant until one of three things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1060
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1061
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1062
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1063
         * <li>The write lock is acquired by the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1064
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1065
         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1066
         * the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1067
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1068
         * <li>The specified waiting time elapses
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1069
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1070
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1071
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1072
         * <p>If the write lock is acquired then the value {@code true} is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1073
         * returned and the write lock hold count is set to one.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1074
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1075
         * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1076
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1077
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1078
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1079
         * <li>has its interrupted status set on entry to this method;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1080
         * or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1081
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1082
         * <li>is {@linkplain Thread#interrupt interrupted} while
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1083
         * acquiring the write lock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1084
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1085
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1086
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1087
         * then {@link InterruptedException} is thrown and the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1088
         * thread's interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1089
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1090
         * <p>If the specified waiting time elapses then the value
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1091
         * {@code false} is returned.  If the time is less than or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1092
         * equal to zero, the method will not wait at all.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1093
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1094
         * <p>In this implementation, as this method is an explicit
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1095
         * interruption point, preference is given to responding to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1096
         * the interrupt over normal or reentrant acquisition of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1097
         * lock, and over reporting the elapse of the waiting time.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1098
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1099
         * @param timeout the time to wait for the write lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1100
         * @param unit the time unit of the timeout argument
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1101
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1102
         * @return {@code true} if the lock was free and was acquired
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1103
         * by the current thread, or the write lock was already held by the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1104
         * current thread; and {@code false} if the waiting time
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1105
         * elapsed before the lock could be acquired.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1106
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1107
         * @throws InterruptedException if the current thread is interrupted
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1108
         * @throws NullPointerException if the time unit is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1109
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1110
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1111
        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1112
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1113
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1114
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1115
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1116
         * Attempts to release this lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1117
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1118
         * <p>If the current thread is the holder of this lock then
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1119
         * the hold count is decremented. If the hold count is now
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1120
         * zero then the lock is released.  If the current thread is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1121
         * not the holder of this lock then {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1122
         * IllegalMonitorStateException} is thrown.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1123
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1124
         * @throws IllegalMonitorStateException if the current thread does not
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1125
         * hold this lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1126
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1127
        public void unlock() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1128
            sync.release(1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1129
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1130
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1131
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1132
         * Returns a {@link Condition} instance for use with this
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1133
         * {@link Lock} instance.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1134
         * <p>The returned {@link Condition} instance supports the same
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1135
         * usages as do the {@link Object} monitor methods ({@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1136
         * Object#wait() wait}, {@link Object#notify notify}, and {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1137
         * Object#notifyAll notifyAll}) when used with the built-in
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1138
         * monitor lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1139
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1140
         * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1141
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1142
         * <li>If this write lock is not held when any {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1143
         * Condition} method is called then an {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1144
         * IllegalMonitorStateException} is thrown.  (Read locks are
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1145
         * held independently of write locks, so are not checked or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1146
         * affected. However it is essentially always an error to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1147
         * invoke a condition waiting method when the current thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1148
         * has also acquired read locks, since other threads that
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1149
         * could unblock it will not be able to acquire the write
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1150
         * lock.)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1151
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1152
         * <li>When the condition {@linkplain Condition#await() waiting}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1153
         * methods are called the write lock is released and, before
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1154
         * they return, the write lock is reacquired and the lock hold
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1155
         * count restored to what it was when the method was called.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1156
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1157
         * <li>If a thread is {@linkplain Thread#interrupt interrupted} while
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1158
         * waiting then the wait will terminate, an {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1159
         * InterruptedException} will be thrown, and the thread's
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1160
         * interrupted status will be cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1161
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1162
         * <li> Waiting threads are signalled in FIFO order.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1163
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1164
         * <li>The ordering of lock reacquisition for threads returning
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1165
         * from waiting methods is the same as for threads initially
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1166
         * acquiring the lock, which is in the default case not specified,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1167
         * but for <em>fair</em> locks favors those threads that have been
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1168
         * waiting the longest.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1169
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1170
         * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1171
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1172
         * @return the Condition object
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1173
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1174
        public Condition newCondition() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1175
            return sync.newCondition();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1176
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1177
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1178
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1179
         * Returns a string identifying this lock, as well as its lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1180
         * state.  The state, in brackets includes either the String
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1181
         * {@code "Unlocked"} or the String {@code "Locked by"}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1182
         * followed by the {@linkplain Thread#getName name} of the owning thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1183
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1184
         * @return a string identifying this lock, as well as its lock state
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1185
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1186
        public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1187
            Thread o = sync.getOwner();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1188
            return super.toString() + ((o == null) ?
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1189
                                       "[Unlocked]" :
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1190
                                       "[Locked by thread " + o.getName() + "]");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1191
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1192
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1193
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1194
         * Queries if this write lock is held by the current thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1195
         * Identical in effect to {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1196
         * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1197
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1198
         * @return {@code true} if the current thread holds this lock and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1199
         *         {@code false} otherwise
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1200
         * @since 1.6
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1201
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1202
        public boolean isHeldByCurrentThread() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1203
            return sync.isHeldExclusively();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1204
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1205
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1206
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1207
         * Queries the number of holds on this write lock by the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1208
         * thread.  A thread has a hold on a lock for each lock action
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1209
         * that is not matched by an unlock action.  Identical in effect
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1210
         * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1211
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1212
         * @return the number of holds on this lock by the current thread,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1213
         *         or zero if this lock is not held by the current thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1214
         * @since 1.6
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1215
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1216
        public int getHoldCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1217
            return sync.getWriteHoldCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1218
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1219
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1220
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1221
    // Instrumentation and status
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1222
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1223
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1224
     * Returns {@code true} if this lock has fairness set true.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1225
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1226
     * @return {@code true} if this lock has fairness set true
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1227
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1228
    public final boolean isFair() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1229
        return sync instanceof FairSync;
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1230
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1231
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1232
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1233
     * Returns the thread that currently owns the write lock, or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1234
     * {@code null} if not owned. When this method is called by a
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1235
     * thread that is not the owner, the return value reflects a
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1236
     * best-effort approximation of current lock status. For example,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1237
     * the owner may be momentarily {@code null} even if there are
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1238
     * threads trying to acquire the lock but have not yet done so.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1239
     * This method is designed to facilitate construction of
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1240
     * subclasses that provide more extensive lock monitoring
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1241
     * facilities.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1242
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1243
     * @return the owner, or {@code null} if not owned
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1244
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1245
    protected Thread getOwner() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1246
        return sync.getOwner();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1247
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1248
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1249
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1250
     * Queries the number of read locks held for this lock. This
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1251
     * method is designed for use in monitoring system state, not for
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1252
     * synchronization control.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1253
     * @return the number of read locks held.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1254
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1255
    public int getReadLockCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1256
        return sync.getReadLockCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1257
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1258
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1259
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1260
     * Queries if the write lock is held by any thread. This method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1261
     * designed for use in monitoring system state, not for
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1262
     * synchronization control.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1263
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1264
     * @return {@code true} if any thread holds the write lock and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1265
     *         {@code false} otherwise
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1266
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1267
    public boolean isWriteLocked() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1268
        return sync.isWriteLocked();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1269
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1270
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1271
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1272
     * Queries if the write lock is held by the current thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1273
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1274
     * @return {@code true} if the current thread holds the write lock and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1275
     *         {@code false} otherwise
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1276
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1277
    public boolean isWriteLockedByCurrentThread() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1278
        return sync.isHeldExclusively();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1279
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1280
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1281
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1282
     * Queries the number of reentrant write holds on this lock by the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1283
     * current thread.  A writer thread has a hold on a lock for
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1284
     * each lock action that is not matched by an unlock action.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1285
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1286
     * @return the number of holds on the write lock by the current thread,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1287
     *         or zero if the write lock is not held by the current thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1288
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1289
    public int getWriteHoldCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1290
        return sync.getWriteHoldCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1291
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1292
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1293
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1294
     * Queries the number of reentrant read holds on this lock by the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1295
     * current thread.  A reader thread has a hold on a lock for
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1296
     * each lock action that is not matched by an unlock action.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1297
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1298
     * @return the number of holds on the read lock by the current thread,
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1299
     *         or zero if the read lock is not held by the current thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1300
     * @since 1.6
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1301
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1302
    public int getReadHoldCount() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1303
        return sync.getReadHoldCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1304
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1305
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1306
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1307
     * Returns a collection containing threads that may be waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1308
     * acquire the write lock.  Because the actual set of threads may
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1309
     * change dynamically while constructing this result, the returned
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1310
     * collection is only a best-effort estimate.  The elements of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1311
     * returned collection are in no particular order.  This method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1312
     * designed to facilitate construction of subclasses that provide
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1313
     * more extensive lock monitoring facilities.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1314
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1315
     * @return the collection of threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1316
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1317
    protected Collection<Thread> getQueuedWriterThreads() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1318
        return sync.getExclusiveQueuedThreads();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1319
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1320
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1321
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1322
     * Returns a collection containing threads that may be waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1323
     * acquire the read lock.  Because the actual set of threads may
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1324
     * change dynamically while constructing this result, the returned
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1325
     * collection is only a best-effort estimate.  The elements of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1326
     * returned collection are in no particular order.  This method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1327
     * designed to facilitate construction of subclasses that provide
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1328
     * more extensive lock monitoring facilities.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1329
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1330
     * @return the collection of threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1331
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1332
    protected Collection<Thread> getQueuedReaderThreads() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1333
        return sync.getSharedQueuedThreads();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1334
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1335
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1336
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1337
     * Queries whether any threads are waiting to acquire the read or
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1338
     * write lock. Note that because cancellations may occur at any
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1339
     * time, a {@code true} return does not guarantee that any other
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1340
     * thread will ever acquire a lock.  This method is designed
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1341
     * primarily for use in monitoring of the system state.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1342
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1343
     * @return {@code true} if there may be other threads waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1344
     *         acquire the lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1345
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1346
    public final boolean hasQueuedThreads() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1347
        return sync.hasQueuedThreads();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1348
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1349
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1350
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1351
     * Queries whether the given thread is waiting to acquire either
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1352
     * the read or write lock. Note that because cancellations may
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1353
     * occur at any time, a {@code true} return does not guarantee
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1354
     * that this thread will ever acquire a lock.  This method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1355
     * designed primarily for use in monitoring of the system state.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1356
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1357
     * @param thread the thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1358
     * @return {@code true} if the given thread is queued waiting for this lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1359
     * @throws NullPointerException if the thread is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1360
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1361
    public final boolean hasQueuedThread(Thread thread) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1362
        return sync.isQueued(thread);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1363
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1364
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1365
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1366
     * Returns an estimate of the number of threads waiting to acquire
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1367
     * either the read or write lock.  The value is only an estimate
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1368
     * because the number of threads may change dynamically while this
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1369
     * method traverses internal data structures.  This method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1370
     * designed for use in monitoring of the system state, not for
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1371
     * synchronization control.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1372
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1373
     * @return the estimated number of threads waiting for this lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1374
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1375
    public final int getQueueLength() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1376
        return sync.getQueueLength();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1377
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1378
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1379
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1380
     * Returns a collection containing threads that may be waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1381
     * acquire either the read or write lock.  Because the actual set
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1382
     * of threads may change dynamically while constructing this
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1383
     * result, the returned collection is only a best-effort estimate.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1384
     * The elements of the returned collection are in no particular
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1385
     * order.  This method is designed to facilitate construction of
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1386
     * subclasses that provide more extensive monitoring facilities.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1387
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1388
     * @return the collection of threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1389
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1390
    protected Collection<Thread> getQueuedThreads() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1391
        return sync.getQueuedThreads();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1392
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1393
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1394
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1395
     * Queries whether any threads are waiting on the given condition
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1396
     * associated with the write lock. Note that because timeouts and
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1397
     * interrupts may occur at any time, a {@code true} return does
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1398
     * not guarantee that a future {@code signal} will awaken any
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1399
     * threads.  This method is designed primarily for use in
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1400
     * monitoring of the system state.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1401
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1402
     * @param condition the condition
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1403
     * @return {@code true} if there are any waiting threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1404
     * @throws IllegalMonitorStateException if this lock is not held
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1405
     * @throws IllegalArgumentException if the given condition is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1406
     *         not associated with this lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1407
     * @throws NullPointerException if the condition is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1408
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1409
    public boolean hasWaiters(Condition condition) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1410
        if (condition == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1411
            throw new NullPointerException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1412
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1413
            throw new IllegalArgumentException("not owner");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1414
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1415
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1416
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1417
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1418
     * Returns an estimate of the number of threads waiting on the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1419
     * given condition associated with the write lock. Note that because
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1420
     * timeouts and interrupts may occur at any time, the estimate
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1421
     * serves only as an upper bound on the actual number of waiters.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1422
     * This method is designed for use in monitoring of the system
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1423
     * state, not for synchronization control.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1424
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1425
     * @param condition the condition
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1426
     * @return the estimated number of waiting threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1427
     * @throws IllegalMonitorStateException if this lock is not held
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1428
     * @throws IllegalArgumentException if the given condition is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1429
     *         not associated with this lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1430
     * @throws NullPointerException if the condition is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1431
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1432
    public int getWaitQueueLength(Condition condition) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1433
        if (condition == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1434
            throw new NullPointerException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1435
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1436
            throw new IllegalArgumentException("not owner");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1437
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1438
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1439
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1440
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1441
     * Returns a collection containing those threads that may be
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1442
     * waiting on the given condition associated with the write lock.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1443
     * Because the actual set of threads may change dynamically while
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1444
     * constructing this result, the returned collection is only a
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1445
     * best-effort estimate. The elements of the returned collection
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1446
     * are in no particular order.  This method is designed to
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1447
     * facilitate construction of subclasses that provide more
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1448
     * extensive condition monitoring facilities.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1449
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1450
     * @param condition the condition
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1451
     * @return the collection of threads
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1452
     * @throws IllegalMonitorStateException if this lock is not held
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1453
     * @throws IllegalArgumentException if the given condition is
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1454
     *         not associated with this lock
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1455
     * @throws NullPointerException if the condition is null
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1456
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1457
    protected Collection<Thread> getWaitingThreads(Condition condition) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1458
        if (condition == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1459
            throw new NullPointerException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1460
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1461
            throw new IllegalArgumentException("not owner");
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1462
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1463
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1464
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1465
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1466
     * Returns a string identifying this lock, as well as its lock state.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1467
     * The state, in brackets, includes the String {@code "Write locks ="}
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1468
     * followed by the number of reentrantly held write locks, and the
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1469
     * String {@code "Read locks ="} followed by the number of held
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1470
     * read locks.
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1471
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1472
     * @return a string identifying this lock, as well as its lock state
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1473
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1474
    public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1475
        int c = sync.getCount();
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1476
        int w = Sync.exclusiveCount(c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1477
        int r = Sync.sharedCount(c);
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1478
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1479
        return super.toString() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1480
            "[Write locks = " + w + ", Read locks = " + r + "]";
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1481
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1482
90ce3da70b43 Initial load
duke
parents:
diff changeset
  1483
}