ReentrantReadWriteLock维护了一对相关的锁:共享锁readLock和独占锁writeLock。共享锁readLock用于读操作,能同时被多个线程获取;独占锁writeLock用于写入操作,只能被一个线程持有。
ReentrantReadWriteLock具有以下几种特性:
- 公平性
- 非公平模式
默认模式。一个持续争用的非公平锁,可能会使其他读线程或写线程无限延期,但它比公平锁有更高的吞吐量。
- 公平模式
当构造一个公平锁时,线程争用使用一个近似顺序到达的策略。当目前持有的锁被释放,要么是等待时间最长的单个写入线程被分配写入锁,或者如果有一组读线程比所有等待写线程等待更长的时间,该组将被分配读取锁。 - 重入性:
ReentrantReadWriteLock允许读线程和写线程重复获取读锁或写锁。当所有写锁都被释放,不可重入读线程才允许获取锁。此外,一个写入线程可以获取读锁,但是一个读线程不能获取写锁。 - 锁降级:
重入性允许从写锁降级到读锁:首先获取写锁,然后获取读锁,然后释放写锁。不过,从一个读锁升级到写锁是不允许的。读锁和写锁在获取过程中都支持中断。 - Condition支持:
Condition只有在写锁中用到,读锁是不支持Condition的
Sync
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.
*/
// 最多支持65535(1<<16-1)个写锁和65535个读锁
// 低16为表示写锁计数,高16为表示持有读锁的线程数
static final int SHARED_SHIFT = 16;
//读锁高16位,读锁个数+1,其实是状态之+2^16
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
//锁最大数量(65535)
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
//写锁掩码,用于标记低16位
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count
* 读锁计数,当前持有读锁的线程数,c的高16位
*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/**
* Returns the number of exclusive holds represented in count
* 写锁计数,也就是它的重入次数,c的低16位
*/
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>
{
//重写初始化方法,在没有进行set的情况下,获取的都是该HoldCounter的值
public HoldCounter initialValue()
{
return new HoldCounter();
}
}
/**
* The number of reentrant read locks held by current thread.
* Initialized only in constructor and readObject.
* Removed whenever a thread's read hold count drops to 0.
*/
private transient ThreadLocalHoldCounter readHolds;
Sync类内部存在两个内部类,分别为HoldCounter和ThreadLocalHoldCounter,用来记录每个线程持有的读锁数量。
ReadLock
public static class ReadLock implements Lock, java.io.Serializable
{
private static final long serialVersionUID = -5992448646407690164L;
//持有的AQS对象
private final ReentrantReadWriteLock.Sync sync;
protected ReadLock(ReentrantReadWriteLock lock)
{
sync = lock.sync;
}
/**
* 获取共享锁
*/
public void lock()
{
sync.acquireShared(1);
}
/**
* 获取共享锁(响应中断)
* @throws InterruptedException
*/
public void lockInterruptibly() throws InterruptedException
{
sync.acquireSharedInterruptibly(1);
}
/**
* 尝试获取共享锁
* @return
*/
public boolean tryLock()
{
return sync.tryReadLock();
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException
{
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* 释放锁
*/
public void unlock()
{
sync.releaseShared(1);
}
/**
* 新建条件
* @return
*/
public Condition newCondition()
{
throw new UnsupportedOperationException();
}
public String toString()
{
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
tryAcquireShared
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();
//持有写锁的线程可以获取读锁,如果获取锁的线程不是current线程;则返回-1
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//获取读锁的数量
int r = sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//首次获取读锁,初始化firstReader和firstReaderHoldCount
if (r == 0)
{
firstReader = current;
firstReaderHoldCount = 1;
}
//当前线程是首个获取读锁的线程
else if (firstReader == current)
{
firstReaderHoldCount++;
}
else
{
//更新cachedHoldCounter
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);
}
-
如果“写锁”已经被持有,这时候可以继续获取读锁,但如果持有写锁的线程不是当前线程,直接返回-1(表示获取失败);
-
如果在尝试获取锁时不需要阻塞等待(由公平性决定),并且读锁的共享计数小于最大数量MAX_COUNT,则直接通过CAS函数更新读取锁的共享计数,最后将当前线程获取读锁的次数+1。
-
如果第二步执行失败,则调用fullTryAcquireShared尝试获取读锁,源码如下:
/**
* 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)
{
//如果获取锁的线程不是current线程,失败
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)
//当前线程持有读锁数为0,移除计数器
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
//超出最大读锁数量
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//CAS更新读锁数量
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;
}
}
}
tryReleaseShared
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;
}
}
Note:在releaseShared中,首先调用tryReleaseShared尝试释放锁,方法流程很简单,主要包括两步:
更新当前线程计数器的锁计数;
CAS更新释放锁之后的state,这里使用了自旋,在state争用的时候保证了CAS的成功执行。