前言
- {@link ReadWriteLock}的实现支持与{@link ReentrantLock}类似的语义。
- 此类具有以下属性:获取顺序此类不对锁定访问强加读取器或写入器首选项顺序。
- 但是,它确实支持可选的公平性政策。
- 非公平模式(默认)当构造为非公平(默认)时,不受重入限制,未指定读写锁的输入顺序。
- 连续竞争的非公平锁可能会无限期地延迟一个或多个读取器或写入器线程,但通常比公平锁具有更高的吞吐量。
- 公平模式公平地构造时,线程使用近似到达顺序策略竞争进入。
- 释放当前持有的锁时,将为等待时间最长的单个写程序线程分配写锁定,或者如果有一组读取器线程的等待时间长于所有等待的写程序线程,则将为该组分配读锁定。
- 如果持有写入锁或有一个正在等待的写入器线程,则试图(非可重入)获取公平读取锁定的线程将阻塞。
- 直到当前等待时间最久的写入器线程获得并释放写入锁后,该线程才会获取读取锁。
- 当然,如果等待中的写作者放弃了等待,将一个或多个阅读器线程留为队列中最长的等待者,并且没有写锁定,那么将为这些阅读器分配读锁定。
- 尝试获取公平的写锁(非可重入)的线程将阻塞,除非读锁和写锁均处于空闲状态(这意味着没有等待的线程)。
- (请注意,非阻塞的{@link ReadLock#tryLock()}和{@link WriteLock#tryLock()}方法不遵循此公平设置,并且如果可能的话,将立即获取锁定,而与等待线程无关)。
- 可重入此锁允许读取器和写入器都以{@link ReentrantLock}的方式重新获取读或写锁。
- 在释放写线程持有的所有写锁之前,不允许非可重入读者。
- 此外,写者可以获取读锁,反之则不能。
- 在其他应用程序中,当在调用或回调对在读锁下执行读取的方法的过程中保持写锁时,重新进入很有用。
- 如果读者试图获取写锁,它将永远不会成功。
- 锁降级Reentrancy还允许先获取写锁,然后再获取读锁,然后释放写锁,从写锁降级为读锁。
- 但是,无法从读取锁升级到写入锁。
- 锁获取的中断读锁和写锁都支持锁获取期间的中断。
- {@link Condition}支持写锁提供了一个{@link Condition}实现,就写锁而言,其行为与{@link ReentrantLock#newCondition}提供的{@link Condition}实现的行为相同。
- {@link ReentrantLock}。
- 当然,此{@link Condition}只能与写锁一起使用。
- 读锁不支持{@link Condition},并且{@code readLock()。
- newCondition()}引发{@code UnsupportedOperationException}。
- 工具此类支持确定是持有锁还是争用锁的方法。
- 这些方法设计用于监视系统状态,而不用于同步控制。
- 此类的序列化与内置锁的行为相同:反序列化的锁处于解锁状态,而不管序列化时的状态如何。
- 用法示例。
- 这是一个代码草图,显示了在更新缓存后如何执行锁降级(以非嵌套方式处理多个锁时,异常处理特别棘手):
-
{@code
- class CachedData {
- Object data;
- volatile boolean cacheValid;
- final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
- void processCachedData() {
-
rwl.readLock().lock();
-
if (!cacheValid) {
-
// Must release read lock before acquiring write lock
-
rwl.readLock().unlock();
-
rwl.writeLock().lock();
-
try {
-
// Recheck state because another thread might have
-
// acquired write lock and changed state before we did.
-
if (!cacheValid) {
-
data = ...
-
cacheValid = true;
-
}
-
// Downgrade by acquiring read lock before releasing write lock
-
rwl.readLock().lock();
-
} finally {
-
rwl.writeLock().unlock(); // Unlock write, still hold read
-
}
-
}
-
try {
-
use(data);
-
} finally {
-
rwl.readLock().unlock();
-
}
- }
- }}
- ReentrantReadWriteLocks可用于提高某些种类的Collection的并发性。
- 仅当预期集合很大,由读取器线程而不是写入器线程访问更多读取器线程,并且需要的操作开销大于同步开销时,这通常才是值得的。
- 例如,这是一个使用TreeMap的类,该类应该很大并且可以同时访问。
-
{@code
- class RWDictionary {
- private final Map<String, Data> m = new TreeMap<String, Data>();
- private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
- private final Lock r = rwl.readLock();
- private final Lock w = rwl.writeLock();
- public Data get(String key) {
-
r.lock();
-
try { return m.get(key); }
-
finally { r.unlock(); }
- }
- public String[] allKeys() {
-
r.lock();
-
try { return m.keySet().toArray(); }
-
finally { r.unlock(); }
- }
- public Data put(String key, Data value) {
-
w.lock();
-
try { return m.put(key, value); }
-
finally { w.unlock(); }
- }
- public void clear() {
-
w.lock();
-
try { m.clear(); }
-
finally { w.unlock(); }
- }
- }}
- 实施说明
- 此锁最多支持65535个递归写锁和65535个读锁。尝试超过这些限制会导致锁定方法抛出{@link Error}。
源码
package java.util.concurrent.locks;
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** Performs all synchronization mechanics */
final Sync sync;
/**
* Creates a new {@code ReentrantReadWriteLock} with
* default (nonfair) ordering properties.
*/
public ReentrantReadWriteLock() {
this(false);
}
/**
* 使用给定的公平性策略创建一个新的{@code ReentrantReadWriteLock}。
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
/**
* Synchronization implementation for ReentrantReadWriteLock.
* Subclassed into fair and nonfair versions.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*
* Read vs write count extraction constants and functions.
* Lock state is logically divided into two unsigned shorts:
* The lower one representing the exclusive (writer) lock hold count,
* and the upper the shared (reader) hold count.
*/
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/**
* A counter for per-thread read hold counts.
* Maintained as a ThreadLocal; cached in cachedHoldCounter
*/
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
/**
* ThreadLocal subclass. Easiest to explicitly define for sake
* of deserialization mechanics.
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
private transient ThreadLocalHoldCounter readHolds;
private transient HoldCounter cachedHoldCounter;
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
/*
* Acquires and releases use the same code for fair and
* nonfair locks, but differ in whether/how they allow barging
* when queues are non-empty.
*/
/**
* Returns true if the current thread, when trying to acquire
* the read lock, and otherwise eligible to do so, should block
* because of policy for overtaking other waiting threads.
*/
abstract boolean readerShouldBlock();
/**
* Returns true if the current thread, when trying to acquire
* the write lock, and otherwise eligible to do so, should block
* because of policy for overtaking other waiting threads.
*/
abstract boolean writerShouldBlock();
/*
* Note that tryRelease and tryAcquire can be called by
* Conditions. So it is possible that their arguments contain
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
private IllegalMonitorStateException unmatchedUnlockException() {
return new IllegalMonitorStateException(
"attempt to unlock read lock, not locked by current thread");
}
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail.
* 2. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 3. If step 2 fails either because thread
* apparently not eligible or CAS fails or count
* saturated, chain to version with full retry loop.
*/
Thread current = Thread.currentThread();
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
/**
* Full version of acquire for reads, that handles CAS misses
* and reentrant reads not dealt with in tryAcquireShared.
*/
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// else we hold the exclusive lock; blocking here
// would cause deadlock.
} else if (readerShouldBlock()) {
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
/**
* Performs tryLock for write, enabling barging in both modes.
* This is identical in effect to tryAcquire except for lack
* of calls to writerShouldBlock.
*/
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != 0) {
int w = exclusiveCount(c);
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
if (!compareAndSetState(c, c + 1))
return false;
setExclusiveOwnerThread(current);
return true;
}
/**
* Performs tryLock for read, enabling barging in both modes.
* This is identical in effect to tryAcquireShared except for
* lack of calls to readerShouldBlock.
*/
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return true;
}
}
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Methods relayed to outer class
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
// Must read state before owner to ensure memory consistency
return ((exclusiveCount(getState()) == 0) ?
null :
getExclusiveOwnerThread());
}
final int getReadLockCount() {
return sharedCount(getState());
}
final boolean isWriteLocked() {
return exclusiveCount(getState()) != 0;
}
final int getWriteHoldCount() {
return isHeldExclusively() ? exclusiveCount(getState()) : 0;
}
final int getReadHoldCount() {
if (getReadLockCount() == 0)
return 0;
Thread current = Thread.currentThread();
if (firstReader == current)
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
return rh.count;
int count = readHolds.get().count;
if (count == 0) readHolds.remove();
return count;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
readHolds = new ThreadLocalHoldCounter();
setState(0); // reset to unlocked state
}
final int getCount() { return getState(); }
}
/**
* Nonfair version of Sync
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* Fair version of Sync
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
/**
* The lock returned by method {@link ReentrantReadWriteLock
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* Acquires the read lock.
*
* <p>Acquires the read lock if the write lock is not held by
* another thread and returns immediately.
*
* <p>If the write lock is held by another thread then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until the read lock has been acquired.
*/
public void lock() {
sync.acquireShared(1);
}
/**
* 获取读取锁,除非当前线程是{@linkplain Thread#interrupt interrupted}。
* 如果写锁没有被另一个线程持有,则获取读锁并立即返回。
* 如果写锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并且在发生以下两种情况之一之前处于休眠状态:读锁由当前线程获取;或某个其他线程{@linkplain Thread#interrupt interrupts}当前线程。
* 如果当前线程:在进入此方法时设置了其中断状态;或在获取读锁时被{@linkplain Thread#interrupt interrupted中断},则抛出{@link InterruptedException}并清除当前线程的中断状态。
* 在此实现中,由于此方法是显式的中断点,因此优先于对中断的响应而不是正常或可重入的锁获取。
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 仅当调用时另一个线程未持有写锁时才获取读锁。
* 如果写锁没有被另一个线程持有,则获取读锁,并立即返回值{@code true}。
* 即使将此锁设置为使用公平的排序策略,对{@code tryLock()}的调用也会立即获取读取锁(如果可用),无论其他线程当前是否在等待读取锁。
* 即使破坏公平性,这种“讨价还价”的行为在某些情况下还是有用的。
* 如果要遵守此锁的公平性设置,请使用几乎等效的{@link
* 如果写锁由另一个线程持有,则此方法将立即返回值{@code false}。
*/
public boolean tryLock() {
return sync.tryReadLock();
}
/**
* 如果在给定的等待时间内另一个线程未持有写锁定,并且当前线程尚未{@linkplain Thread#interrupt interrupted},则获取读锁定。
* 如果写锁没有被另一个线程持有,则获取读锁,并立即返回值{@code true}。
* 如果将此锁设置为使用公平的排序策略,那么如果有任何其他线程在等待该锁,则不会获取可用锁。
* 这与{@link
* 如果您想要一个定时的{@code tryLock}确实允许在公平锁上插入,则将定时和非定时表单组合在一起:
*
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
*
* 如果写锁由另一个线程持有,则当前线程将出于线程调度目的而被禁用,并且在发生以下三种情况之一之前,它处于休眠状态:或其他某个线程{@linkplain Thread#interrupt interrupts}当前线程;或经过了指定的等待时间。
* 如果获取了读锁,则返回值{@code true}。
* 如果当前线程:在进入此方法时设置了其中断状态;或在获取读锁时被{@linkplain Thread#interrupt interrupted中断},则抛出{@link InterruptedException}并清除当前线程的中断状态。
* 如果经过了指定的等待时间,则返回值{@code false}。
* 如果时间小于或等于零,则该方法将根本不等待。
* 在此实现中,由于此方法是显式的中断点,因此优先于对中断的响应而不是正常或可重入的锁定获取,而是优先报告等待时间的流逝。
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* Attempts to release this lock.
*
* <p>If the number of readers is now zero then the lock
* is made available for write lock attempts.
*/
public void unlock() {
sync.releaseShared(1);
}
/**
* Throws {@code UnsupportedOperationException} because
* {@code ReadLocks} do not support conditions.
*
* @throws UnsupportedOperationException always
*/
public Condition newCondition() {
throw new UnsupportedOperationException();
}
/**
* Returns a string identifying this lock, as well as its lock state.
* The state, in brackets, includes the String {@code "Read locks ="}
* followed by the number of held read locks.
*
* @return a string identifying this lock, as well as its lock state
*/
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
/**
* The lock returned by method {@link ReentrantReadWriteLock
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* 获取写锁。
* 如果读取和写入锁定均未由另一个线程持有,则获取写入锁定并立即返回,将写入锁定保持计数设置为1。
* 如果当前线程已经持有写锁,则持有计数将增加一,该方法将立即返回。
* 如果锁是由另一个线程持有的,则当前线程将出于线程调度目的而被禁用,并处于休眠状态,直到获取了写入锁为止,此时写入锁的保持计数被设置为1。
*/
public void lock() {
sync.acquire(1);
}
/**
* 除非当前线程为{@linkplain Thread#interrupt interrupted},否则获取写锁定。
* 如果读取和写入锁定均未由另一个线程持有,则获取写入锁定并立即返回,将写入锁定保持计数设置为1。
* 如果当前线程已经持有此锁,则持有计数将增加一,并且该方法将立即返回。
* 如果该锁由另一个线程持有,则出于线程调度的目的,当前线程将被禁用,并处于休眠状态,直到发生以下两种情况之一:当前线程获取了写锁;或某个其他线程{@linkplain Thread#interrupt interrupts}当前线程。
* 如果当前线程获取了写锁定,则将锁定保持计数设置为1。
* 如果当前线程:在进入此方法时设置了其中断状态;或在获取写锁定时被{@linkplain Thread#interrupt interrupted中断},则抛出{@link InterruptedException}并清除了当前线程的中断状态。
* 在此实现中,由于此方法是显式的中断点,因此优先于对中断的响应而不是正常或可重入的锁获取。
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 仅当调用时另一个线程未持有该写锁时,才获取该写锁。
* 如果读取和写入锁定均未由另一个线程持有,则获取写入锁定,并立即返回值{@code true},并将写入锁定保持计数设置为1。
* 即使已将此锁设置为使用公平的排序策略,无论是否有其他线程当前正在等待写锁,对{@code tryLock()}的调用都将立即获取该锁(如果有)。
* 即使破坏公平性,这种“讨价还价”的行为在某些情况下还是有用的。
* 如果要遵守此锁的公平性设置,请使用几乎等效的{@link
* 如果当前线程已经持有此锁,则持有计数将增加一,并且该方法返回{@code true}。
* 如果锁由另一个线程持有,则此方法将立即返回值{@code false}。
*/
public boolean tryLock( ) {
return sync.tryWriteLock();
}
/**
* 如果在给定的等待时间内另一个线程未持有该写锁,并且当前线程尚未{@linkplain Thread#interrupt interrupted},则获取该写锁。
* 如果读取和写入锁定均未由另一个线程持有,则获取写入锁定,并立即返回值{@code true},并将写入锁定保持计数设置为1。
* 如果将此锁设置为使用公平的排序策略,则如果任何其他线程正在等待写锁,则不会获取可用锁。
* 这与{@link
* 如果您想要一个定时的{@code tryLock}确实允许在公平锁上插入,则将定时和非定时表单组合在一起:
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
* 如果当前线程已经持有此锁,则持有计数将增加一,并且该方法返回{@code true}。
* 如果该锁由另一个线程持有,则当前线程将出于线程调度目的而被禁用,并且在发生以下三种情况之一之前,它处于休眠状态:或其他某个线程{@linkplain Thread#interrupt interrupts}当前线程;或经过指定的等待时间。
* 如果获得了写锁,则返回值{@code true},并将写锁保持计数设置为1。
* 如果当前线程:在进入此方法时设置了其中断状态;或在获取写锁定时被{@linkplain Thread#interrupt interrupted中断},则抛出{@link InterruptedException}并清除了当前线程的中断状态。
* 如果经过了指定的等待时间,则返回值{@code false}。
* 如果时间小于或等于零,则该方法将根本不等待。
* 在此实现中,由于此方法是显式的中断点,因此优先于对中断的响应而不是正常或可重入的锁定获取,而是优先报告等待时间的流逝。
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 尝试释放此锁。
* 如果当前线程是此锁的持有者,则保留计数将减少。
* 如果保持计数现在为零,则释放锁定。
* 如果当前线程不是此锁的持有者,则将引发{@link IllegalMonitorStateException}。
*/
public void unlock() {
sync.release(1);
}
/**
* 返回与此{@link Lock}实例一起使用的{@link Condition}实例。
* 返回的{@link Condition}实例与{@link Object}监视方法({@link Object#wait()wait},{@ link Object#notify notify}和{@link Object#notifyAll当与内置监视器锁定一起使用时)。
* 如果在调用任何{@link Condition}方法时未保留此写锁定,则会引发{@link IllegalMonitorStateException}。
* (读锁独立于写锁而持有,因此不会被检查或受影响。
* 但是,当当前线程也已获取读锁时,调用条件等待方法本质上总是错误,因为其他可能解除阻塞它的线程不会被调用。
* 能够获取写锁。
* )调用条件{@linkplain Condition#await()等待}方法时,写锁被释放,并且在返回之前,将重新获取写锁,并将锁的保持计数恢复到原来的状态。
* 何时调用该方法。
* 如果线程在等待时被{@linkplain Thread#interrupt interrupted中断},则等待将终止,将引发{@link InterruptedException}并清除线程的中断状态。
* 等待线程以FIFO顺序发出信号。
* 从等待方法返回的线程的锁重新获取顺序与最初获取锁的线程的顺序相同(默认情况下未指定),但对于公平锁,优先使用等待时间最长的线程。
*/
public Condition newCondition() {
return sync.newCondition();
}
/**
* Returns a string identifying this lock, as well as its lock
* state. The state, in brackets includes either the String
* {@code "Unlocked"} or the String {@code "Locked by"}
* followed by the {@linkplain Thread
*
* @return a string identifying this lock, as well as its lock state
*/
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
/**
* 查询此写锁是否由当前线程持有。
* 与{@link ReentrantReadWriteLock#isWriteLockedByCurrentThread}有效。
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
*
* 查询当前线程对该写锁的保留数。
* 对于每个未与解锁动作匹配的锁定动作,线程都会拥有一个锁。
* 与{@link ReentrantReadWriteLock#getWriteHoldCount}有效。
*/
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
// Instrumentation and status
/**
* Returns {@code true} if this lock has fairness set true.
*
* @return {@code true} if this lock has fairness set true
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回当前拥有写锁的线程;如果不拥有,则返回{@code null}。
* 当非所有者的线程调用此方法时,返回值反映当前锁定状态的尽力而为近似。
* 例如,即使有线程试图获取锁,但所有者尚未拥有所有者,所有者可能会暂时{@code null}。
* 设计此方法是为了便于构造提供更广泛的锁监视功能的子类。
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 查询为此锁持有的读取锁的数量。
* 此方法设计用于监视系统状态,而不用于同步控制。
*/
public int getReadLockCount() {
return sync.getReadLockCount();
}
/**
* 查询写锁是否由任何线程持有。
* 此方法设计用于监视系统状态,而不用于同步控制。
*/
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
/**
* Queries if the write lock is held by the current thread.
*
* @return {@code true} if the current thread holds the write lock and
* {@code false} otherwise
*/
public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询当前线程对该锁持有的重入写入次数。
* 对于未与解锁动作匹配的每个锁定动作,编写器线程均拥有一个锁保持状态。
*/
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
/**
* 查询当前线程对该锁持有的可重入读取次数。
* 对于与解锁操作不匹配的每个锁定操作,读取器线程均具有锁定的保持状态。
*/
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
/**
* 返回一个包含可能正在等待获取写锁的线程的集合。
* 因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。
* 返回的集合的元素没有特定的顺序。
* 设计此方法是为了便于构造提供更广泛的锁监视功能的子类。
*/
protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
/**
* 返回一个包含可能正在等待获取读锁的线程的集合。
* 因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。
* 返回的集合的元素没有特定的顺序。
* 设计此方法是为了便于构造提供更广泛的锁监视功能的子类。
*/
protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
/**
* 查询是否有任何线程正在等待获取读或写锁。
* 请注意,由于取消可能随时发生,因此{@code true}返回值不能保证任何其他线程都将获得锁。
* 此方法主要设计用于监视系统状态。
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 查询给定线程是否正在等待获取读取或写入锁定。
* 请注意,由于取消可能随时发生,因此{@code true}返回值不能保证此线程将获得锁。
* 此方法主要设计用于监视系统状态。
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 返回等待获取读或写锁的线程数的估计值。
* 该值只是一个估计值,因为在此方法遍历内部数据结构时,线程数可能会动态变化。
* 此方法设计用于监视系统状态,而不用于同步控制。
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回一个包含可能正在等待获取读或写锁的线程的集合。
* 因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。
* 返回的集合的元素没有特定的顺序。
* 设计此方法是为了便于构造子类,以提供更广泛的监视功能。
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 查询是否有任何线程正在等待与写锁关联的给定条件。
* 请注意,由于超时和中断可能随时发生,因此{@code true}返回并不保证将来的{@code signal}会唤醒任何线程。
* 此方法主要设计用于监视系统状态。
*/
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回在与写锁关联的给定条件下等待的线程数的估计值。
* 请注意,由于超时和中断可能随时发生,因此估算值仅用作实际侍者数的上限。
* 此方法设计用于监视系统状态,而不用于同步控制。
*/
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回一个包含那些可能正在等待与写锁关联的给定条件的线程的集合。
* 因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。
* 返回的集合的元素没有特定的顺序。
* 设计此方法是为了便于构造提供更广泛的状态监视工具的子类。
*/
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回标识此锁定及其锁定状态的字符串。
* 括号中的状态包括字符串{@code“ Write locks =”},后跟可重入的写入锁的数量,字符串{@code“ Read locks =”},后跟持有的读取锁的数量。
*/
public String toString() {
int c = sync.getCount();
int w = Sync.exclusiveCount(c);
int r = Sync.sharedCount(c);
return super.toString() +
"[Write locks = " + w + ", Read locks = " + r + "]";
}
/**
* 返回给定线程的线程ID。
* 我们必须直接访问它,而不是通过方法Thread.getId()来访问它,因为getId()不是最终的,并且已知它会以不保留唯一映射的方式被覆盖。
*/
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset
(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
}