package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.lang.reflect.Field;
import java.util.Collection;
/**
* 这是接口{@link ReadWriteLock}的实现类,支持类似于{@link ReentrantLock}的语义.
* <p>这个类具有下面的属性:
*
* <ul>
* <li><b>锁获取顺序</b>
*
* <p>这个类不受锁访问的读写锁偏好顺序影响.然而,它支持可选的<em>公平(fairness)</em>策略.
*
* <dl>
* <dt><b><i>非公平模式(Non-fair mode) (默认)</i></b>
* <dd>当构造为非公平锁(默认)时, 读锁和写锁的进入顺序是未指定的,受限于可重入性约束.
* 竞争非公平锁可能会无限期延迟一个或多个读线程或写线程,但通常比公平锁有更高的吞吐量.
*
* <dt><b><i>公平模式(Fair mode)</i></b>
* <dd>当构造为公平锁时,线程竞争使用近似于到达顺序(arrival-order)策略.
* 当释放当前持有的锁时,要么等待时间最长的写线程被分配写锁,要么一组比所有等待写线程等待时间都长的读线程被分配读锁.
*
* <p>如果写锁被持有或者存在等待写线程,尝试获取公平的读锁(不可重入)的线程会阻塞.
* 这个线程不会获得读锁,直到当前最老的等待写线程获得写锁并释放.当然,如果某个等待写
* 线程放弃等待,一个或多个读线程成为队列中等待写锁释放的时间最长的线程,那么读线程都将被分配读锁.
*
* <p>尝试获取公平的写入锁(不可重入)的线程将会被阻塞,除非读锁和写锁都是自由状态(这隐含着没有等待线程).(注意非阻塞的{@link ReadLock#tryLock()}和{@link WriteLock#tryLock()}方法不受公平设置的影响,如果可能的话,不管是否有等待线程这两个方法都会立即获得锁.
* <p>
* </dl>
*
* <li><b>可重入性(Reentrancy)</b>
*
* <p>这个锁允许读锁和写锁以{@link ReentrantLock}方式重新获取读锁或写锁.
* 不可重入的读线程不被允许,直到写线程持有的所有写锁都被释放.
*
* <p>此外,写线程可以获取读锁,但反之不行.在一些应用中,可重入性是很有用的,如当在持有写锁时
* 调用执行在读锁下的读操作的方法.如果读线程尝试获取写锁,它永远也不会成功.
*
* <li><b>锁降级(Lock downgrading)</b>
* <p>可重入性也允许从写锁降级为读锁,先获取写锁,然后获取读锁,再然后释放写锁.
* 然而,从读锁升级为写锁是<b>不可能的</b>.
*
* <li><b>锁获取中断</b>
* <p>读锁和写锁都支持在锁获取过程中中断.
*
* <li><b>{@link Condition}支持</b>
* <p>写锁提供了{@link Condition}实现,它的行为与{@link ReentrantLock#newCondition}提供的 {@link Condition}实现相同
* 这个{@link Condition}当然只能用于写锁.
*
* <p>读锁不支持{@link Condition},调用{@code readLock().newCondition()}会抛出{@code UnsupportedOperationException}.
*
* <li><b>仪器(Instrumentation)</b>
* <p>这个类支持确定是否锁被持有或被竞争的方法.这些方法用于监视系统状态,不用于同步控制.
* </ul>
*
* <p>这个类的序列化行为与内置的锁相同:反序列化得到的锁处于未锁定状态,不管序列化时是什么状态.
*
* <p><b>用法示例</b>. 下面是一个代码骨架,演示了如何在更新缓存之后执行锁降级(
* 当以非嵌套方式处理多个锁时,异常处理需要一些特殊的技巧:
*
* <pre> {@code
* class CachedData {
* Object data;
* volatile boolean cacheValid;
* final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
*
* void processCachedData() {
* rwl.readLock().lock();
* if (!cacheValid) {
* // 在获取写锁之前必须释放读锁
* rwl.readLock().unlock();
* rwl.writeLock().lock();
* try {
* // 重新检查状态,因为另一个线程可能获取了写锁并在我们之前修改了状态.
* if (!cacheValid) {
* data = ...
* cacheValid = true;
* }
* // 在释放写锁之前获取读锁进行降级
* rwl.readLock().lock();
* } finally {
* rwl.writeLock().unlock(); // 释放写锁,仍然持有读锁
* }
* }
*
* try {
* use(data);
* } finally {
* rwl.readLock().unlock();
* }
* }
* }}</pre>
*
* ReentrantReadWriteLocks可以用于提升一些集合使用场景的并发性.
* 这通常只在集合很大,且访问它的读线程比写线程多,需要使用开销大于同步开销的操作时是有用的.
* 例如,下面是一个使用很大的TreeMap且并发访问的类.
*
* <pre> {@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(); }
* }
* }}</pre>
*
* <h3>实现注意事项</h3>
*
* <p>这个锁支持最大65535个递归写锁和65535个读锁。尝试超过这些限制将导致在锁定方法中抛出{@link Error}.
*
* @since 1.5
* @author Doug Lea
*/
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
/** 内部类,提供读锁 */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** 内部类,提供写锁 */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** 执行所有的同步机制 */
final Sync sync;
/**
* 创建具有默认排序属性(非公平)的新{@code ReentrantReadWriteLock}实例.
*/
public ReentrantReadWriteLock() {
this(false);
}
/**
* 创建具有给定的公平策略的新{@code ReentrantReadWriteLock}实例.
*
* @param fair {@code true} 如果这个锁应该使用公平排序策略
*/
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; }
/**
* ReentrantReadWriteLock的同步实现. 创建的子类有公平版本和非公平版本.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*
* 读与写锁的数量提取常量和函数.
* 锁定状态逻辑上分为两个无符号短整型(unsigned shorts):
* 较低的整型表示独占(写)锁的持有数量,
* 较高的整型表示共享(读)锁的持有数量.
*/
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;
/** 返回count中表示共享锁持有的数量 */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** 返回count中表示独占锁持有的数量 */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/**
* 用于每一个线程读锁持有数量的计算器.
* 用ThreadLocal维护; 缓存到cachedHoldCounter
*/
static final class HoldCounter {
int count = 0;
// 使用线程的id, 而不是引用, 避免垃圾保留
final long tid = getThreadId(Thread.currentThread());
}
/**
* ThreadLocal子类. 显示定义反序列化机制.
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
* 当前线程持有的可重入读锁的数量.
* 只在构造器和readObject中初始化.
* 当线程的读锁持有数量减小到0时,要移除.
*/
private transient ThreadLocalHoldCounter readHolds;
/**
* 成功获取读锁的最后一个线程的持有数量.
* 在通常情况下,下一个要释放的线程是最后一个要获取的线程,这样做可以节省ThreadLocal查找时间.
* 这是非易失性的,因为它只是用作启示规则,非常适合线程缓存.
*
* <p>可以延长线程的存活时间,它缓存了读锁持有数量, 但是可以通过不保留线程的引用避免垃圾保留.
*
* <p>通过良性的数据竞争访问; 依赖内存模型的final字段和out-of-thin-air(无中生有)保证.
*/
private transient HoldCounter cachedHoldCounter;
/**
* firstReader是第一个获取读锁的线程.
* firstReaderHoldCount是firstReader的持有数量.
*
* <p>更准确地说,firstReader是最后一个将共享数量从0改为1的唯一线程, 且从此没有释放过读锁.
* 如果没有这样的线程,那么它的值为null.
*
* <p>不能导致垃圾保留,除非线程终止时没有释放读锁,由于tryReleaseShared将它设置为null.
*
* <p>通过良性的数据竞争访问;依赖内存模型的(无中生有)out-of-thin-air保证引用.
*
* <p>这使得跟踪非争用读锁的读持有数量代价很小.
*/
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
/*
* 公平锁和非公平锁的获取和释放使用相同的代码.
* 但是不同点在于,当队列非空时,是否/如何允许闯入(抢占)(barging).
*/
/**
* 如果当前线程尝试获取读锁且其它线程有资格这样做, 那么当前线程应该阻塞.
* 因为策略是超过其它等待线程.
*/
abstract boolean readerShouldBlock();
/**
* 如果当前线程尝试获取写锁且其它线程有资格这样做,那么当前线程应该阻塞.
* 因为策略是超过其它等待线程.
*/
abstract boolean writerShouldBlock();
/*
* 注意tryRelease和tryAcquire可以被Condition调用.
* 所以有可能它们的参数包含Condition等待过程中释放的和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) {
/*
* 代码流程:
* 1. 如果读锁持有数量非零或者写锁持有数量非零,且锁拥有者不是当前线程,则获取失败.
* 2. 如果count已经饱和(达到最大值)(这只可能发生在count已经非零的情况)
* 3. 否则,这个线程有资格获取这个锁,如果它是一个可重入获取或者排队策略允许.如果是这样,更新state状态,并将当前线程设置为owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
// c不为0,说明已经有线程持有读锁或者写锁
if (c != 0) {
// (注意: if c != 0 and w == 0 那么共享锁的count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 如果获取锁后的读占锁的数量大于最大数量,则报Error,超过最大锁数量
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 可重入获取写锁
setState(c + acquires);
return true;
}
// 如果c为0,说明没有线程持有读锁或者写锁
// 如果写线程需要阻塞,或者修改state状态失败,则获取失败
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
// 如果写线程不需要阻塞,且修改state状态成功,则将当前线程设置为owner
setExclusiveOwnerThread(current);
// 返回获取锁成功
return true;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
// 如果当前线程是第一个获取共享锁的线程,即firstReader
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
// 如果缓存的holder不存在,或者属于当前线程,则从readHolds中查找
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
// 如果count已经是1或者0了,那么直接从readHolds删除对应的线程记录
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
// 将当前线程持有读锁的数量减1
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// 释放读锁对读线程没有影响,
// 但是如果读写锁都空闲的话,可能允许等待的写线程继续执行
// nextc等于0表示当前已经没有读线程占用共享锁,写线程可以获取独占锁了
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) {
/*
* 代码流程:
* 1. 如果另一个线程持有写锁,那么该方法获取共享锁失败.
* 2. 否则,该线程就有资格锁定wrt状态,所以根据队列策略判断是否应该阻塞.
* 如果不需要阻塞,尝试比较并交换state状态,并更新锁持有数量.
* 注意,这一步没有检查可重入获取读锁,这被推迟到完全版本,
* 以避免在更多典型的非重入场景下检查持有数量.
* 3. 如果步骤2失败,可能因为线程明确没有资格(需要阻塞等待),或CAS失败(其它线程并发修改),
* 或共享锁持有数量饱和(锁持有数量达到最大值65535),则进入完全重试循环版本.
*/
Thread current = Thread.currentThread();
int c = getState();
// 如果另一个线程持有写锁, 即独占锁数量不等于0且不是当前线程,那么该方法获取共享锁失败
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) {
// 第一个线程可重入的获取读锁,读锁持有数量加1
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);
}
/**
* 获取读锁的完全版本, 处理CAS丢失,可重入读锁,这些都没有在tryAcquireShared中处理.
*/
final int fullTryAcquireShared(Thread current) {
/*
* 这部分代码相对于tryAcquireShared有点冗余,
* 但是总的来说,它简化了tryAcquireShared与重试和延迟读取持有数量的交互.
*/
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// 否则如果是当前线程持有独占锁,在这里阻塞将导致死锁.
} 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;
}
}
}
/**
* 尝试获取写锁, 在两种模式下使能barging.
* 该方法与tryAcquire效果是相同的,除了没有调用writerShouldBlock外.
*/
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
// state状态不等于0表示已经有其它线程持有写锁或者读锁
if (c != 0) {
// 获取独占锁的数量
int w = exclusiveCount(c);
// 独占锁的数量等于0,或者独占的线程不是当前线程,则返回false,表示获取写锁失败
// 如果w == 0表示同步器Sync的读锁被其它线程持有,而读写锁要互斥,因此写锁获取失败
// 如果current != getExclusiveOwnerThread()表示已经有其它线程持有写锁了,而写锁与写锁要互斥,因此写锁获取失败
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 如果当前线程是该写锁的独占线程,且锁持有数量达到最大的65535, 则报Error错误
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
// state状态等于0表示没有其它线程持有写锁或者读锁,那么将state状态加1
if (!compareAndSetState(c, c + 1))
return false; // 如果有其它线程并发获取了写锁或读锁,则当前线程获取写锁失败
// 将当前线程设置为该写锁的独占拥有者线程
setExclusiveOwnerThread(current);
// 返回当前线程获取写锁成功
return true;
}
/**
* 执行尝试获取读锁,使能在共享模式和独占模式下的闯入(抢占)(barging).
* 该方法与tryAcquireShared效果是相同的,除了没有调用readerShouldBlock.
*/
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
// 如果独占锁(写锁)被其它线程持有且当前线程不是独占锁拥有者线程,则获取共享锁(读锁)失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
// 获取共享锁的使用数量
int r = sharedCount(c);
// 如果共享锁数量的达到最大值65535,则报Error
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// CAS占用共享锁,如果有其它读线程也在获取共享锁,则下面的if的测试条件有可能为false
// 需要执行for循环再次尝试获取共享锁,只要共享锁可用,则一定可以获取成功
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++;
}
// 返回true,表示尝试获取读锁成功
return true;
}
}
}
protected final boolean isHeldExclusively() {
// 我们通常必须在获取拥有者之前读取state状态, 我们无需检查当前线程是否是拥有者
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Methods relayed to outer class
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
// 获取owner之前必须读取state状态,确保内存一致性
// 首先判断是否有线程持有独占锁,有线程持有独占锁的数量不为0,则返回独占拥有者线程,否则返回null
return ((exclusiveCount(getState()) == 0) ?
null :
getExclusiveOwnerThread());
}
final int getReadLockCount() {
// 共享锁的持有数量
return sharedCount(getState());
}
final boolean isWriteLocked() {
// 独占锁的持有数量不为0,就表示写锁是被锁定的
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;
}
/**
* 从流中重新构造该实例,即反序列化.
*/
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(); }
}
/**
* Sync的非公平版本
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // 写线程总是可以闯入(抢占)barge
}
final boolean readerShouldBlock() {
/*
* 为了避免写线程无限期饥饿, 如果暂时出现在等待队列的头结点的线程(如果存在的话)是一个等待中的写线程,
* 那么当前读线程阻塞.
* 这只是一个随机的效果,因为在等待队列中,如果等待的写线程排在其它读线程之后,那么新的读线程不会阻塞.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* Sync的公平版本
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
/**
* {@link ReentrantReadWriteLock#readLock}方法返回的锁.
*/
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 外部锁对象
* @throws NullPointerException 如果lock是null
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* 获取读锁.
*
* <p>如果写锁没有被另一个线程持有,那么就获得读锁,并立即返回.
*
* <p>如果写锁被另一个线程持有,那么当前线程就会被禁止调度,休眠直到获取到读锁.
*/
public void lock() {
sync.acquireShared(1);
}
/**
* 获取读锁,除非当前线程被中断{@linkplain Thread#interrupt interrupted}.
*
* <p>如果写锁没有被另一个线程持有,那么就获得读锁,并立即返回.
*
* <p>如果写锁被另一个线程持有,那么当前线程就会被禁止调度,休眠直到发生下面的事情之一:
*
* <ul>
*
* <li>当前线程获得读锁
*
* <li>其它线程中断{@linkplain Thread#interrupt interrupts}当前线程.
*
* </ul>
*
* <p>如果当前线程:
*
* <ul>
*
* <li>在进入该方法时设置了中断状态
*
* <li>获取读锁时被中断{@linkplain Thread#interrupt interrupted}
*
* </ul>
*
* 那么该线程会抛出{@link InterruptedException}中断异常,当前线程的中断状态被清除.
*
* <p>在这个实现中,由于该方法是一个明确的中断点,所以会优先响应中断,而不是优先获取锁.
*
* @throws InterruptedException 如果当前线程被中断
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 在调用该方法时,写锁没有被另一个线程持有,那么就获得读锁.
*
* <p>如果写锁没有被另一个线程持有,那么该方法获取读锁,并立即返回true.
* 即使当这个锁设置使用公平的排序策略,调用{@code tryLock()}也
* <em>将</em>立即获取读锁,只要读锁可用,不管是否有其它的线程正在等待读锁.
* 这种"闯入(抢占)(barging)"行为在特定场景下是很有用的, 即使它破坏了公平性.
* 如果你想要尊重公平性设置,那么使用{@link #tryLock(long, TimeUnit)
* tryLock(0, TimeUnit.SECONDS) },几乎是等价的(它也检测中断).
*
* <p>如果写锁被另一个线程持有,那么该方法会立即返回{@code false}.
*
* @return {@code true} 如果获得了读锁,则返回true
*/
public boolean tryLock() {
return sync.tryReadLock();
}
/**
* 如果在给定的等待时间内,没有另一个线程持有写锁,且当前线程没有被中断,那么就获得读锁.
*
* <p>如果写锁没有被另一个线程持有,那么该方法获取读锁,并立即返回true.
* 如果这个锁被设置使用公平的排序策略,那么如果有其它线程也在等待这个锁,那么当前线程不会获得锁.
* 这与{@link #tryLock()}方法时相反的.
* 如果你想要的一个限时的{@code tryLock},且允许在公平锁上的闯入(抢占),那么可以将限时和不限时形式组合在一起使用.
*
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
*
* <p>如果写锁被另一个线程持有,那么当前线程就被禁止线程调度,休眠直到下列三件事之一发生:
*
* <ul>
*
* <li>当前线程获得读锁
*
* <li>其它线程中断当前线程
*
* <li>指定的等待时间已经过了
*
* </ul>
*
* <p>如果获得了读锁,则返回{@code true}.
*
* <p>如果当前线程:
*
* <ul>
*
* <li>在进入该方法时设置了中断状态
*
* <li>或者在获取读锁时被中断
*
* </ul> 那么当前线程抛出{@link InterruptedException}中断异常,当前线程的中断状态被清除.
*
* <p>如果指定的超时时间已经过了,那么返回{@code false}.
* 如果时间小于等于0,那么该方法不会执行等待.
*
* <p>在这个实现中,由于该方法是明确的中断点,所以优先响应中断,
* 而不是优先获取读锁或者报告等待超时.
*
* @param timeout 等待读锁的超时时间
* @param unit 超时参数的时间单位
* @return {@code true} 如果获得了读锁,则返回true
* @throws InterruptedException 如果当前线程被中断
* @throws NullPointerException 如果时间单位是null
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* 尝试释放读锁.
*
* <p>如果读线程数量限制是0,那么写锁可以尝试使用.
*/
public void unlock() {
sync.releaseShared(1);
}
/**
* 抛出{@code UnsupportedOperationException}异常,因为{@code ReadLocks}不支持条件.
*
* @throws UnsupportedOperationException 总是抛出
*/
public Condition newCondition() {
throw new UnsupportedOperationException();
}
/**
* 返回这个锁的字符串标识,包括它的锁的状态.
* 在方括号里,状态,包括字符串{@code "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 + "]";
}
}
/**
* {@link ReentrantReadWriteLock#writeLock}方法返回的锁.
*/
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 外部的锁对象
* @throws NullPointerException 如果lock是null
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* 获取写锁.
*
* <p>如果没有另一个线程持有读锁或者写锁,那么就获取写锁,设置写锁持有数量为1, 并立即返回.
*
* <p>如果当前线程已经持有这个写锁,那么写锁持有数量会增加1,该方法立即返回.
*
* <p>如果写锁被另一个线程持有,那么当前线程禁止参与线程调度,并阻塞,直到写锁被释放,此时写锁持有数量设置为1.
*/
public void lock() {
sync.acquire(1);
}
/**
* 获取写锁,除非当前线程被中断({@linkplain Thread#interrupt interrupted}).
*
* <p>如果没有另一个线程持有读锁或者写锁,那么就获取写锁,设置写锁持有数量为1, 并立即返回.
*
* <p>如果当前线程已经持有这个写锁,那么写锁持有数量会增加1,该方法立即返回.
*
* <p>如果写锁被另一个线程持有,那么当前线程禁止参与线程调度,并阻塞,直到下面两件事情之一发生:
*
* <ul>
*
* <li>当前线程获得写锁
*
* <li>其它线程中断了当前线程{@linkplain Thread#interrupt interrupts}
*
* </ul>
*
* <p>如果当前线程获得写锁,那么锁持有数量设置为1.
*
* <p>如果当前线程:
*
* <ul>
*
* <li>在进入该方法时设置了中断状态
* or
*
* <li>或者正在获取写锁时被中断{@linkplain Thread#interrupt interrupted}
*
* </ul>
*
* 那么就会抛出{@link InterruptedException},当前线程中断状态被清除.
*
* <p>在这个实现中,由于该方法是明确的中断点,所以优先响应中断,还不是优先正常的或重入地获取该锁.
*
* @throws InterruptedException 如果当前线程被中断
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 只有在调用该方法时没有另一个线程持有该写锁才获得这个写锁.
*
* <p>如果没有另一个线程持有读锁或写锁,那么该方法就获得写锁,并立即返回{@code true},
* 设置写锁持有数量为1. 如果锁可用的话,即使这个锁使用的是公平排序策略,调用{@code tryLock()}也<em>将</em>立即获取锁,
* 不管当前是否有其它线程正在等待写锁. 在特定场景下,这种"闯入(抢占)barging"是很有用的,即使它破坏了公平性.
* 如果你想要尊重该锁的公平性设置,那么使用{@link#tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) },
* 这个方法是等价的(它也会检测中断).
*
* <p>如果当前线程已经持有该锁,那么持有数量会加1,该方法返回{@code true}.
*
* <p>如果另一个线程持有该锁,那么这个方法会立即返回{@code false}.
*
* @return {@code true} 如果该锁空闲并曾被当前线程获取过,或者当前线程已经获取了该写锁,则返回true;否则返回false.
*/
public boolean tryLock( ) {
return sync.tryWriteLock();
}
/**
* 如果在给定的等待时间内没有另一个线程持有写锁,且当前线程没有被中断,则获得写锁.
*
* <p>如果其它线程既没有持有读锁,也没有持有写锁,那么就获得写锁,并立即返回{@code true}.
* 设置写锁持有数量为1.
* 如果这个锁设置使用公平的排序策略,那么有其它的线程正在等待写锁,那么当前线程也不会获得这个可用的锁.
* 这与{@link #tryLock()}方法相反.如果你想要一限时的{@code tryLock},且允许在公平锁上闯入(抢占),
* 如果你想要的一个限时的{@code tryLock},且允许在公平锁上的闯入(抢占),那么可以将限时和不限时形式组合在一起使用:
*
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
*
* <p>如果当前线程已经持有这个锁,那么持有数量加1,该方法返回{@code true}.
*
* <p>如果这个锁被另一个线程持有,那么当前线程将被禁止线程调度,休眠直到下面的三件事情之一发生:
*
* <ul>
*
* <li>当前线程获得了写锁
*
* <li>或者其它线程中断了当前线程
*
* <li>指定的等待超时时间过了
*
* </ul>
*
* <p>如果获得了写锁,那么该方法返回{@code true},写锁持有数量设置为1.
*
* <p>如果当前线程:
*
* <ul>
*
* <li>在进入该方法时设置了中断状态
*
* <li>或者正在获取写锁时被中断{@linkplain Thread#interrupt interrupted}
*
* </ul>
*
* 那么就会抛出{@link InterruptedException},当前线程中断状态被清除.
*
* <p>在这个实现中,由于该方法是明确的中断点,所以优先响应中断,还不是优先正常的或重入地获取该锁.
*
* <p>如果指定的超时时间已经过了,那么返回{@code false}.
* 如果时间小于等于0,那么该方法不会执行等待.
*
* <p>在这个实现中,由于该方法是明确的中断点,所以优先响应中断,
* 而不是优先获取锁或者报告等待超时.
*
* @param timeout 等待写锁的超时时间
* @param unit timeout参数的时间单位
*
* @return {@code true} 如果锁时空闲的,且被当前线程获取了,则返回true;
* 或者写锁已经被当前线程持有;如果在获得锁之前超时了,那么返回{@code false}
*
* @throws InterruptedException 如果当前线程被中断
* @throws NullPointerException 如果时间单位是null
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 尝试释放这个锁.
*
* <p>如果当前线程是这个锁的持有者,那么持有数量减1.
* 如果持有数量现在是0,那么释放这个锁.
* 如果当前线程不是这个锁的持有者,那么抛出 {@link IllegalMonitorStateException}异常.
*
* @throws IllegalMonitorStateException 如果当前线程不持有该锁
*/
public void unlock() {
sync.release(1);
}
/**
* 返回一个{@link Condition}实例,
* <p>返回的{@link Condition}实例支持的用法类似于内置监视器锁中使用的{@link Object} 监视器方法 ({@link
* Object#wait() wait}, {@link Object#notify notify}, 和 {@link
* Object#notifyAll notifyAll}).
*
* <ul>
*
* <li>如果该写锁没有被任何线程持有,那么调用该{@link Condition}上的方法会抛出{@link
* IllegalMonitorStateException}异常.
* (读锁被持有与写锁是独立的,所以不受检查, 不影响。不过,当当前线程也获得了读锁时,
* 调用condition的wait方法有必要总是一个错误,因为其它可以解锁读锁的线程将不能获取写锁).
*
* <li>当调用condition {@linkplain Condition#await() waiting}方法时,写锁被释放,
* 在它们返回之前,写锁又重新获取,锁持有数量恢复到调用await方法时的数量.
*
* <li>如果在等待时线程被中断,那么等待也被终止,并抛出中断异常,线程的中断状态被清除.
*
* <li> 等待线程按照先进先出(FIFO)顺序通知.
*
* <li>从waiting方法返回后的线程获取锁的顺序与这些线程初始获取锁的顺序相同,这是默认的场景.
* 但是对于 <em>公平</em>锁,更优先考虑等待时间最长的线程.
*
* </ul>
*
* @return the Condition object
*/
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#getName name} of the owning 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() + "]");
}
/**
* Queries if this write lock is held by the current thread.
* Identical in effect to {@link
* ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
*
* @return {@code true} if the current thread holds this lock and
* {@code false} otherwise
* @since 1.6
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* Queries the number of holds on this write lock by the current
* thread. A thread has a hold on a lock for each lock action
* that is not matched by an unlock action. Identical in effect
* to {@link ReentrantReadWriteLock#getWriteHoldCount}.
*
* @return the number of holds on this lock by the current thread,
* or zero if this lock is not held by the current thread
* @since 1.6
*/
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
// 测试与状态
/**
* 如果公平性设置为true,则返回{@code true}.
*
* @return {@code true} if this lock has fairness set true
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回当前拥有写锁的线程,如果没有线程拥有写锁,则返回{@code null}.
* 当该方法由不是拥有者的线程调用时,返回的值反映的是当前锁状态的近似值.
* 例如,即使有线程正在尝试获取锁,但是还没有得到.When this method is called by a
* 设计该方法时为了帮助构造子类,以提供更多的锁监控工具.
*
* @return the owner, or {@code null} if not owned
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 查询为该锁持有的读锁的数量. 这个方法设计的目的是用于监控系统状态,不用于同步控制.
* @return 持有的读锁的数量
*/
public int getReadLockCount() {
return sync.getReadLockCount();
}
/**
* 查询是否写锁被某个线程持有. 这个方法设计的目的是用于监控系统状态,不用于同步控制.
*
* @return {@code true} if any thread holds the write lock and
* {@code false} otherwise
*/
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
/**
* 查询是否写锁被当前线程持有.
*
* @return 如果当前先吃持有写锁, 返回{@code true} , 否则,返回{@code false}
*/
public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询当前线程持有该锁上的可重入写锁的数量.
* 写线程为每一个未匹配unlock动作的lock动作持有一个锁.
*
* @return 当前线程持有的写锁的数量,如果当前线程没有持有写锁,则返回0
*/
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
/**
* 查询当前线程持有该锁上的可重入读锁的数量.
* 读线程为每一个未匹配unlock动作的lock动作持有一个锁.
*
* @return 当前线程持有的读锁的数量,如果当前线程没有持有读锁,则返回0
* @since 1.6
*/
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
/**
* 返回一个包含等待获取写锁的线程集合.
* 因为实际的线程集可能会在构造这个结果时动态改变,所以返回的集合只是一个最优估计值.
* 返回集合中的元素是没有特定顺序的. 设计该方法是为了帮助构造子类以提供更多锁监控工具.
*
* @return 线程集合Collection
*/
protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
/**
* 返回一个包含等待获取读锁的线程集合.
* 因为实际的线程集可能会在构造这个结果时动态改变,所以返回的集合只是一个最优估计值.
* 返回集合中的元素是没有特定顺序的. 设计该方法是为了帮助构造子类以提供更多锁监控工具.
*
* @return 线程集合Collection
*/
protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
/**
* 查询是否有某个线程正在等待获取读锁或者写锁.
* 注意,由于可能在任意时刻取消等待, 因此返回true不保证有其它线程已经获取到了锁.
* 这个方法主要用于监控系统状态.
*
* @return {@code true} 如果有其它线程正在等待获取锁
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 查询是否给定的线程正在等待获取读锁或者写锁.
* 注意,由于可能在任意时刻取消等待, 因此返回true不保证有这个线程已经获取到了锁.
* 这个方法主要用于监控系统状态.
*
* @param thread the thread
* @return {@code true} 如果有thread线程正在等待获取锁
* @throws NullPointerException if the thread is null
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 返回等待获取读锁或写锁的线程的数量的估计值.
* 返回的值只是一个估计值,因为在这个方法遍历内部数据结构时,线程数量可能会动态变化.
* 这个方法设计的目的是用于监控系统状态,不用于同步控制.
*
* @return 等待这个锁的线程数量的估计值
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回可能包含等待获取读锁或写锁的线程的集合.
* 因为实际的线程集可能会在构造这个结果时动态改变,所以返回的集合只是一个最优估计值.
* 返回集合中的元素是没有特定顺序的. 设计该方法是为了帮助构造子类以提供更多锁监控工具.
*
* @return the collection of threads
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 查询是否有线程正在等待给定的与写锁有关的条件.
* 注意,因为超时和中断可能随时发生,返回true不保证将来的signal会唤醒任何线程.
* 这个方法设计的目的是用于监控系统状态.
*
* @param condition the condition
* @return {@code true} 如果没有任何等待的线程
* @throws IllegalMonitorStateException 如果没有持有这个锁
* @throws IllegalArgumentException 如果给定的条件与这个锁无关
* @throws NullPointerException 如果condition是null
*/
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);
}
/**
* 返回等待与写锁有关的条件的线程的数量的估计值.
* 等待给定的与写锁有.
* 注意,因为超时和中断可能随时发生,这个估计值只是实际等待线程数量的上限.
* 这个方法设计的目的是用于监控系统状态,不用于同步控制.
*
* @param condition the condition
* @return 等待线程的估计数量
* @throws IllegalMonitorStateException 如果没有持有这个锁
* @throws IllegalArgumentException 如果给定条件与这个锁无关
* @throws NullPointerException 如果condition是null
*/
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);
}
/**
* 返回包含等待与写锁有关的条件的线程的集合.
* 因为实际的线程集可能会在构造这个结果时动态改变,所以返回的集合只是一个最优估计值.
* 设计该方法是为了帮助构造子类以提供更多condition监控工具.
*
* @param condition the condition
* @return 线程集合
* @throws IllegalMonitorStateException 如果这个锁没有持有
* @throws IllegalArgumentException 如果给定的条件与这个锁无关
* @throws NullPointerException 如果condition是null
*/
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 ="}紧跟持有读锁的数量.
*
* @return a string identifying this lock, as well as its lock state
*/
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,即tid字段的值. 我们必须直接访问tid,而不是通过Thread.getId()方法.
* 因为getId()不是final的,已经知道它可能会被覆写,不再维持唯一映射关系.
*/
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
}
// Unsafe机制
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 (Throwable e) {
throw new Error(e);
}
}
}