ReentrantReadWriteLock 源码解析
ReentrantReadWriteLock 源码解析
ReentrantReadWriteLock 类描述
ReadWriteLock 的实现支持与 ReentrantLock 相似的语义。
该类具有以下属性:
获取顺序:
这个类不会对锁访问施加读取器或写入器的优先顺序。但是,它确实支持一个可选的公平策略。
-
非公平模式(默认):
当构造为非公平(默认)时,读写锁的进入顺序是未指定的,受重入约束。持续竞争的非公平锁可能无限期地推迟一个或多个读线程或写线程,但通常比公平锁具有更高的吞吐量。
-
公平模式:
当构造为公平时,线程使用近似到达顺序策略竞争进入。当释放当前保持的锁时,要么为等待时间最长的单个写线程分配写锁,要么为一组等待时间比所有等待写线程都长的读线程分配读锁。
如果有写锁被持有,或者有一个等待的写线程,那么试图获取公平读锁(不可重入)的线程将阻塞。在当前最老的等待写线程获取并释放写锁之前,线程不会获取读锁。当然,如果一个正在等待的写线程放弃了等待,让一个或多个读线程作为队列中等待时间最长的写锁空闲的线程,那么这些读线程将被分配读锁。
可重入:
这个锁允许读取者和写入者以 ReentrantLock 的方式重新获得读锁或写锁。在写线程持有的所有写锁释放之前,不允许使用不可重入读取器。
此外,写程序可以获得读锁,但反之亦然。在其他应用程序中,当对在读锁下执行读操作的方法的调用或回调期间持有写锁时,重入可能很有用。如果一个读取器试图获取写锁,它将永远不会成功。
锁降级:
重入还允许将写锁降级为读锁,方法是先获取写锁,再获取读锁,然后释放写锁。但是,从读锁升级到写锁是不可能的。
锁获取中断:
读锁和写锁都支持在锁获取期间中断。
Condition 支持:
写锁提供了一个实现 Condition 的方法,其行为与 ReentrantLock 实现的 Condition 的方法相同。当然,这个 Condition 只能与写锁一起使用。
读锁不支持 Condition 并且调用 readLock(). newcondition() 时抛出 UnsupportedOperationException。
仪器仪表:
该类支持确定锁是否被持有或竞争的方法。这些方法是为监控系统状态而设计的,而不是为同步控制而设计的。
这个类的序列化与内置锁的行为相同:反序列化的锁处于未锁定状态,无论其序列化时的状态如何。
示例用法:
下面是一个代码草图,展示了如何在更新缓存后执行锁降级(在以非嵌套方式处理多个锁时,异常处理特别棘手):
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 可用于改善某些集合在某些情况下的并发性。通常,只有在期望集合很大、由比写入线程更多的读取器线程访问,并且需要开销超过同步开销的操作时才值得。例如,下面是一个使用TreeMap的类,该类被期望是大的和并发访问的。
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个读锁。如果试图超过这些限制,则会导致锁定方法抛出 Error 。
ReentrantReadWriteLock 源代码
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
/**
* 内部类提供的读锁
*/
private final ReadLock readerLock;
/**
* 内部类提供的写锁
*/
private final WriteLock writerLock;
/**
* 执行所有同步机制
*/
final Sync sync;
/**
* 无参构造(默认非公平锁)
*/
public ReentrantReadWriteLock() {
this(false);
}
/**
* 有参构造,创建公平或非公平锁
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public WriteLock writeLock() {
return writerLock;
}
public ReadLock readLock() {
return readerLock;
}
/**
* ReentrantReadWriteLock 的同步实现。分为公平版和非公平版。
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*
* 锁状态在逻辑上分为两个无符号短路,用一个 int 值(32 位)表示:
*
* 低 16 位表示 写锁的保持计数(包括重入)
* 高 16 位表示 读锁的保持计数(包括重入)
*/
/**
* 共享锁的长度
*/
static final int SHARED_SHIFT = 16;
/**
* 共享锁 增量或者减量
*/
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
/**
* 共享持有数的最大值(包含重入)
*/
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
/**
* 00000000 00000000 11111111 11111111 独占锁掩码
*/
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/**
* 返回共享锁的保持数
*/
static int sharedCount(int c) {
return c >>> SHARED_SHIFT;
}
/**
* 返回独占锁的保持数
*/
static int exclusiveCount(int c) {
return c & EXCLUSIVE_MASK;
}
/**
* 每线程读取保持计数的计数器。保持为ThreadLocal;缓存在cachedHoldCounter中
*/
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
/**
* ThreadLocal子类。为了反序列化机制,最容易显式定义
*/
static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
//初始化调用,当ThreadLocalHoldCounter为null,获取时,会执行初始化
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
* 当前线程持的保持数。 仅在构造函数和readObject中初始化。
* 每当线程的读取保持计数降至0时,就会删除。
*/
private transient ThreadLocalHoldCounter readHolds;
/**
* 上一个成功获取readLock的线程的保持计数
* 在通常情况下,下一个释放的线程是最后一个获取的线程,这样就节省了ThreadLocal查找。
* 这是非易失的,因为它只是用作启发式方法,并且非常适合线程缓存。
*
* 1.可以比它正在缓存读取保持计数的线程活得更长,但通过不保留对线程的引用来避免垃圾保留。
* 2.通过良性数据竞争访问;依赖于记忆模型的最终场和凭空保证。
*/
private transient HoldCounter cachedHoldCounter;
/**
* firstReader是第一个获得读锁的线程。firstReaderHoldCount 是第一个读取器的保持数。
*
* 1.更准确地说,firstReader是最后一个将共享计数从0改为1的唯一线程,并且从那时起没有释放读锁;如果没有这样的线程,则为null。
* 2.由于tryreleasshared将其设置为null,除非线程终止而没有释放它的读锁,否则不会导致垃圾保留。
* 3.通过良性数据竞争访问;依赖于内存模型的凭空保证作为参考。
* 4.这使得对非竞争读锁的读持有的跟踪非常便宜。
*/
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
/*
* 公平锁和非公平锁的获取和释放使用相同的代码,但它们在队列非空时是否允许转换上有所不同。
*/
/**
* 正在尝试获取读锁的线程是否应该阻塞(阻塞返回 true):
* 公平模式:等待队列中存在线程,则当前应阻塞。
* 非公平模式:如果明显的第一个排队线程(如果存在)正在以独占模式等待,则当前应阻塞。
*/
abstract boolean readerShouldBlock();
/**
* 正在尝试获取写锁的线程是否应该阻塞(阻塞返回 true):
* 公平模式:等待队列中存在线程,则当前应阻塞。
* 非公平模式:不阻塞,返回 false。
*/
abstract boolean writerShouldBlock();
/**
* 释放独占锁
*/
protected final boolean tryRelease(int releases) {
// 判断当前线程是否是持有锁的线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//状态值 - 1
int nextc = getState() - releases;
// 如果为 0 释放当前锁
// 非 0 表示重入了多次,state 状态值 -1 即可
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
/**
* 尝试获取独占锁
*/
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
// c != 0 表示存在锁
if (c != 0) {
// c != 0 and w = 0 表示 有读锁
// current != getExclusiveOwnerThread() 判断当前线程是否持有锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// c != 0 and w != 0 表示有 写锁;
// 上一步已经判断当前线程,持有锁。准备进行重入
// 判断是否大于最大重入次数
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 重入
setState(c + acquires);
return true;
}
// c == 0 说明当前锁,未被占有
// writerShouldBlock 公平锁,返回是否等待队列有等待的线程。如果有等待的线程,则直接返回false;如果没有通过CAS 获取锁,
// writerShouldBlock 非公平锁,返回 false,直接通过CAS获取锁
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;
// 第一个线程的保持数是 1 设置 firstReader = null
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--; // 第一个线程重入的情况 firstReaderHoldCount--
} else {
// 如果是其他线程释放锁时
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
// 如果当前线程的保持计数小于等于 1,则移除当前线程的保持数
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
// 否则 count--
--rh.count;
}
// 设置状态值 - SHARED_UNIT
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) {
Thread current = Thread.currentThread();
int c = getState();
// 存在写锁 并且 写锁的持有者不是自己 则返回-1
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
return -1;
// 获取当前持有读锁线程的个数
int r = sharedCount(c);
// 1.readerShouldBlock() 根据读锁阻塞策略,不阻塞的情况下
// 2.r < MAX_COUNT 读锁的个数小于最大值
// 3.CAS 方法设置 读锁数 + 1
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);
}
/**
* 完全尝试获取共享锁(CAS 方式处理未能获取共享锁的线程)
*/
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();
// 存在独占锁,独占锁不是当前线程,返回 -1
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// 否则我们持有独占锁;这里的阻塞会导致死锁。
// else we hold the exclusive lock; blocking here
// would cause deadlock.
} else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly
// 确保我们没有再次获取读锁
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != 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;
}
}
}
/**
* 尝试获取写锁
*/
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;
}
/**
* 尝试获取读锁
*/
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");
//CAS 尝试获取读锁
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() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
// =========================================== 传递给外部类的方法 =================================
// Methods relayed to outer class
final ConditionObject newCondition() {
return new ConditionObject();
}
/**
* 获取锁的持有者
*/
final 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();
}
}
/**
* Sync的非公平版本
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
/**
* 写线程总是保持 false,不应该阻塞
*/
final boolean writerShouldBlock() {
return false; // writers can always 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();
}
}
/**
* 方法 ReentrantReadWriteLock.readLock() 返回的读锁。
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
/**
* 子类使用的构造函数
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* 获取读取锁。
* 1.如果另一个线程未持有写锁,则获取读锁并立即返回。
* 2.如果写锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到获取读锁。
*/
public void lock() {
sync.acquireShared(1);
}
/**
* 除非当前线程被中断,否则获取读取锁。
* 1.如果另一个线程未持有写锁,则获取读锁并立即返回。
* 2.如果写锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:
* 读取锁由当前线程获取;或 其他线程中断当前线程。
* 3.如果当前线程:在进入该方法时设置其中断状态;或在获取读锁时被中断,则抛出 InterruptedException,并清除当前线程的中断状态。
* 4.在这个实现中,由于该方法是一个显式中断点,因此优先考虑响应中断,而不是正常或可重入获取锁。
*
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 仅当在调用时另一个线程未持有写锁时,才获取读锁。
*
* 1.如果写锁没有被其他线程持有,则获取读锁,并立即返回值 true。即使该锁被设置为使用公平排序策略,如果读锁可用,调用 tryLock() 也会立即获得该读锁,无论当前是否有其他线程在等待该读锁。
* 这个 barging;行为在某些情况下是有用的,即使它破坏了公平。如果您想遵守此锁的公平设置,请使用几乎等同的 tryLock(long,TimeUnit) tryLock(0,TimeUnit.SECONDS)(它也检测中断)。
* 2.如果写锁由另一个线程持有,则此方法将立即返回值 false。
*/
public boolean tryLock() {
return sync.tryReadLock();
}
/**
* 如果在给定的等待时间内另一个线程未持有写锁,并且当前线程未被中断,则获取读锁。
*
* 1.如果另一个线程未持有写锁,则获取读锁,并立即返回值 true。
* 如果此锁已设置为使用公平排序策略,则如果任何其他线程正在等待该锁,则不会获取可用的锁。这与 tryLock()方法相反。
* 如果你想要一个定时的 tryLock 允许闯入一个公平锁,可以将定时和非定时的形式结合在一起:
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
*
* 2.如果写锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一:
* 读取锁由当前线程获取;或其他一些线程中断当前线程;或指定的等待时间已过。
*
* 3.如果获取了读锁,则返回值 true。
* 4.如果当前线程:在进入该方法时设置其中断状态;或在获取读锁时被中断,则抛出InterruptedException,并清除当前线程的中断状态。
* 5.如果经过了指定的等待时间,则返回值 false 。如果时间小于或等于零,则该方法根本不会等待。
* 6.在该实现中,由于该方法是一个显式中断点,因此优先考虑响应中断而不是正常或可重入获取锁,以及报告等待时间的流逝。
*/
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);
}
/**
* 读锁不支持 Condition
*/
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
/**
* 方法 ReentrantReadWriteLock.writeLock() 返回的写锁。
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
/**
* 子类使用的构造函数
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
*
* 获取写锁。
* 1.如果读锁和写锁都没有被另一个线程持有,则获取写锁,并立即返回,将写锁持有计数设置为1。
* 2.如果当前线程已经持有写锁,那么保持计数将增加1,方法将立即返回。
* 3.如果锁由另一个线程持有,则当前线程出于线程调度的目的而被禁用,并且处于休眠状态,直到获取了写锁,此时写锁持有计数被设置为1。
*/
public void lock() {
sync.acquire(1);
}
/**
* 除非当前线程被中断,否则获取写锁。
* 1.如果读锁和写锁都没有被另一个线程持有,则获取写锁,并立即返回,将写锁持有计数设置为1。
* 2.如果当前线程已经持有该锁,则持有计数将增加1,方法将立即返回。
* 3.如果锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:写锁由当前线程获取;或其他线程 中断 当前线程。
* 4.如果当前线程获取了写锁,则锁保持计数设置为1。
* 5.如果当前线程:在进入该方法时设置其中断状态;或在获取写锁时被中断,则抛出 InterruptedException,并清除当前线程的中断状态。
* 6.在这个实现中,由于该方法是一个显式中断点,因此优先考虑响应中断,而不是正常或可重入获取锁。
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 仅当在调用时另一个线程未持有写锁时,才获取写锁。
*
* 1.如果读锁和写锁都没有被另一个线程持有,则获取写锁,并立即返回值 true,将写锁持有计数设置为1。
* 即使此锁已设置为使用公平排序策略,调用 tryLock() 也会立即获取可用的锁,无论其他线程当前是否正在等待写锁。
* 这个 barging 行为在某些情况下是有用的,即使它破坏了公平。
* 如果您想遵守此锁的公平性设置,请使用几乎等同的 tryLock(long,TimeUnit) tryLock(0,TimeUnit.SECONDS)(它也检测中断)。
* 2.如果当前线程已经持有此锁,则持有计数将增加1,方法返回 true。
* 3.如果锁由另一个线程持有,则此方法将立即返回值 false。
*/
public boolean tryLock() {
return sync.tryWriteLock();
}
/**
* 如果在给定的等待时间内另一个线程未持有写锁,并且当前线程未被 中断,则获取写锁。
*
* 1.如果读锁和写锁都没有被其他线程持有,则获取写锁,并立即返回值为 true,将写锁保持计数设置为1。
* 如果此锁已设置为使用公平排序策略,则如果任何其他线程正在等待写锁,则不会获取可用的锁。这与 tryLock() 方法相反。
* 如果你想要一个定时的 tryLock 允许闯入一个公平锁,可以将定时和非定时的形式结合在一起:
* <pre> {@code
* if (lock.tryLock() ||
* lock.tryLock(timeout, unit)) {
* ...
* }}</pre>
*
* 2.如果当前线程已经持有此锁,则持有计数将增加1,方法返回 true。
* 3.如果锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一:
* 写锁由当前线程获取;或其他一些线程中断当前线程;或指定的等待时间已过
* 4.如果获取了写锁,则返回值 true,并将写锁保持计数设置为1。
* 5.如果当前线程:在进入该方法时设置其中断状态;或在获取写锁时被中断,则抛出 InterruptedException,并清除当前线程的中断状态。
* 6.如果经过了指定的等待时间,则返回值 false。如果时间小于或等于零,则该方法根本不会等待。
* 7.在该实现中,由于该方法是一个显式中断点,因此优先考虑响应中断而不是正常或可重入获取锁,以及报告等待时间的流逝。
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 尝试释放此锁。
*
* 如果当前线程是此锁的持有者,那么将减少持有者计数。如果保持计数现在为零,则解除锁定。
* 如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException 。
*/
public void unlock() {
sync.release(1);
}
/**
* 返回一个用于Lock 实例的 Condition 实例。
* 当与内置监视器锁一起使用时,返回的 Condition 实例支持与 Object 监视器方法(Object.wait()、Object.notify()和object.notifyAll()相同的用法。
*
* 1.如果在调用任何 Condition 方法时未保持此写锁,则会引发 IllegalMonitorStateException。
* (读锁是独立于写锁而持有的,因此不会被检查或影响。但是,当当前线程也获取了读锁时,调用条件等待方法本质上总是一个错误,因为其他可以解除锁定的线程将无法获取写锁。)
* 2.当调用条件 Condition.await()方法时,将释放写锁,在它们返回之前,将重新获取写锁,并将锁保持计数恢复到调用该方法时的状态。
* 3.如果线程在等待时被中断,那么等待将终止,将抛出 InterruptedException,并清除线程的中断状态。
* 4.等待线程按FIFO顺序发出信号。
* 5.从等待方法返回的线程重新获取锁的顺序与最初获取锁的线程相同,默认情况下没有指定,但对于公平锁优先于那些等待时间最长的线程。
*/
public Condition newCondition() {
return sync.newCondition();
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
/**
* 查询当前线程是否持有此写锁。与 ReentrantReadWriteLock.isWriteLockedByCurrentThread 的效果相同。
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询当前线程对此写锁的保留数。线程对每个锁操作都持有一个锁,而锁操作与解锁操作不匹配。效果与ReentrantReadWriteLock.getWriteHoldCount相同。
*/
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
// ============================================= 仪表和状态 ========================================
// Instrumentation and status
/**
* 公平锁返回 true
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回当前拥有写锁的线程,没有则返回 null
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 获取读锁保持数(当前有多少读线程获取了该锁)
*/
public int getReadLockCount() {
return sync.getReadLockCount();
}
/**
* 查询写锁是否由任何线程持有
*/
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
/**
* 查询当前线程是否持有写锁。
*/
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();
}
/**
* 查询是否有线程正在等待获取读或写锁
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 查询给定线程是否正在等待获取读锁或写锁。
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 返回等待获取读或写锁的线程数的估计值。
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回一个集合,该集合包含可能正在等待获取读锁或写锁的线程。
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 查询是否有线程正在等待与写锁相关联的给定条件。
*/
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);
}
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 {
// TODO: 注释源码
// UNSAFE = sun.misc.Unsafe.getUnsafe();
//TODO:新增 初始化 unsafe 基于反射获取Unsafe实例
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
UNSAFE = (Unsafe) f.get(null);
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset
(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
}