ReentranReadWriteLock源码分析
构造函数
public ReentrantReadWriteLock() {
this(false); // 可以看出读写锁默认是非公平锁
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);//readLock类的初始化
writerLock = new WriteLock(this);writeLock类的初始化
}
//ReadLock,WriteLock内部类
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
从上面可以看出ReentrantReadWriteLock,ReadLock,WriteLock共有一个Sync对象
Sync类
sync类继承自AbstractQueuedSynchronizer (Java的Lock的底层基础)
FINAL/常量
static final int SHARED_SHIFT = 16; //将32Bit的高16位表示读锁状态,低16位表示写锁状态
static final int SHARED_UNIT = (1 << SHARED_SHIFT); //高16位,用于操作读锁次数
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; //可重入锁的最高次数
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//可以用来获取写锁的次数
ThreadLocalHoldCounter类用来记录每个线程获取锁的次数;目的是缓存上一次获取锁线程的状态。
当在 获取->释放 读锁这段时间,如果没有其他线程获取读锁的话,此缓存就能帮助提高性能
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
private transient ThreadLocalHoldCounter readHolds; //用一个 ThreadLocal 来记录当前线程持有的读锁数量
private transient HoldCounter cachedHoldCounter; //用来缓存上一次缓存的线程状态
写锁的获取与释放(core) 【相对读锁简单】
**释放**
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; // true 写锁都释放完了;false当前线程还握着锁
}
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 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;
}
在非公平锁中
final boolean writerShouldBlock() {
return false; // writers can always barge
}
在公平锁中
final boolean writerShouldBlock() {
return hasQueuedPredecessors(); //按顺序获取
}
可以看到这里的实现完全与ReentranLock中一样
读锁的获取与释放(core)
**读锁释放**
protected final boolean tryReleaseShared(int unused) {//释放
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null; // firstReader用来记录第一次获取读锁的线程,因此锁次数减少至零,firstReader就可以置为null
else
firstReaderHoldCount--;
} else {
//当前线程不是第一次获取读锁的线程
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();//表示暂无缓存ThreadLocalHoldCounter 或者当前线程不是缓存类;则取出
int count = rh.count;
if (count <= 1) {
readHolds.remove(); //移除当前线程在ThreadLocal中保存的状态,**防止内存泄露**
if (count <= 0)
throw unmatchedUnlockException(); //有个二货多少unlock();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT; //SHARED_UNIT高16位的值,减去相当于低16减1
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;
}
}
**读锁的获取**
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
if (exclusiveCount(c) != 0 && //这里表明有写锁,并且独占线程不是当前线程
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c); //这里表明两种状态,1.无写锁 或者当前线程就是独占的线程
if (!readerShouldBlock() && //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;
}
如果到这里的就表明两种情况 1. readerShouldBlock返回true 2.compareAndSetState失败
return fullTryAcquireShared(current); //这个函数的目的是再一次进行CAS,为了效率而生,不能因为一个CAS就把我拒之门外
}
Fair锁 //这个与写线程类似
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
//不公平锁,这个就与写线程不同了
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.
*/
//上面翻译过来就是:如果阻塞线程中的head是写线程,我就放弃了;防止新的读锁与写锁进行争抢,这就避免了写锁的饿死
return apparentlyFirstQueuedIsExclusive();
}
//这四个if翻译过来就是,头结点不为null&&头结点的子结点不为null&&头结点的子结点是可以共享的吗&&头结点的子结点的线程不为空 -》返回true
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
未完待续
锁降级: 将持有写锁的线程,去获取读锁的过程被称为锁降级
无锁升级