ReentrantReadWriteLock 是java的读写锁
ReentrantReadWriteLock类的定义
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
/** 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;
- 只是实现了ReadWriteLock接口
- 三个重要的字段readerLock , writerLock 和sync 都是重要的内部类
###ReadWriteLock接口内部就是定义了两个方法如下
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
ReentrantReadWriteLock的构造方法
第二个构造方法中给readerLock 和writerLock两个字段进行了设值
/**
* Creates a new {@code ReentrantReadWriteLock} with
* default (nonfair) ordering properties.
*/
public ReentrantReadWriteLock() {
this(false);
}
/**
* Creates a new {@code ReentrantReadWriteLock} with
* the given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
##内部类WriteLock
/**
* The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
###WriteLock#lock方法
public void lock() {
sync.acquire(1);
}
acquire是Sync的方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- lock方法与ReentrantLock 中的lock方法没有区别, 主要区别体现在tryAcquire 方法吧
###Sync.tryAcquire方法
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); // exclusiveCount 就是去掉传入的int的最高两位字节, 只取最低两位的字节
if (c != 0) { // 如果计数器不是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;
}
// 计数器为0
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires)) // 非公平锁writerShouldBlock 会直接返回false. 不会继续
return false; // 公平锁会判断当前节点是否是第二节点, 不是第二节点或者第二节点为null, 则会进入compareAndSetState方法, 尝试进行获取锁, 获取失败进入if 中 ??????? 为何不是第二几点会尝试获取锁
setExclusiveOwnerThread(current); // 设置当前线程是获取锁的线程
return true;
}
writerShouldBlock方法, 在FairSync和NofairSync中表现不一样
-
NofairSync 中writerShouldBlock 会直接返回false.
-
FairSync中writerShouldBlock方法, 会调用AQS中的hasQueuedPredecessors 方法
public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
###WriteLock#unlock方法
public void unlock() {
sync.release(1);
}
sync.release方法
public final boolean release(int arg) {
if (tryRelease(arg)) { //释放锁
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); // 唤醒链表第二个节点
return true;
}
return false;
}
sync.tryRelease 方法
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively()) //判断当前获取锁的线程是否是当前线程
throw new IllegalMonitorStateException();
int nextc = getState() - releases; // 计数器减值
boolean free = exclusiveCount(nextc) == 0;
if (free) //判断计数器减去releases后值是否为0
setExclusiveOwnerThread(null); //为0就是所有的锁都释放了
setState(nextc); // 设值
return free;
}
- 这个线程后面都计数器的修改都不用考虑同步问题, 因为只有当前获取锁的线程才能继续进行操作
##内部类ReadLock
###类的定义
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync 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;
}
###ReadLock.lock 方法
读锁才能体现出来变化了
/**
* 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);
}
调用的是sync.acquireShared方法
sync.acquireShared
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0) //tryAcquireShared 获取读锁失败 就会进入if中
doAcquireShared(arg); // 这里的逻辑与重入锁一致, 都是请求获取锁, 判断是否是第二位, 尝试获取下, 获取失败就会进入parkAndCheckInterrupt 方法沉睡, 沉睡后等待自己变成第二位被唤醒
}
Sync.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();
//a
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) //a 计数器不是0, 当前线程不是获取锁线程
return -1; //返回-1
//b
int r = sharedCount(c); //右移16位
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) { // 读锁直接从第三个字节开始加起吗
if (r == 0) { // 为何c右移16位后等于0 . 说明当前线程可以获取读锁. 读计数器为0
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { //当前线程就是获取第一个获取读锁的线程,
firstReaderHoldCount++; // 计数器直接加
} else {
//(c)
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); //这个方法逻辑与上面逻辑一样, 只是多了个循环请求
}
- exclusiveCount© != 0 判断写锁 是否已经被获取了, 所以(a)处if判断是否获取读锁被获取, 且不是当前线程获取的,
- (b) 处将c 计数器右移16位, 应该是把c 的高两位作为读锁计数器, 低的两位作为写锁计数器, 这样的实现 不知为何
- 代码运行到c处, 说明当前锁是读锁, 但是当前线程不是第一个获取读锁的线程, 所以从cachedHoldCounter取出来计数器. 这个计数器使用ThreadLocal 实现, 表示的是当前线程的获取读锁的数量, 与state 不一样, state 的高位记录的是读锁的所有线程的合计
- 读锁获取的时候需要判断当前锁的状态, 如果是写锁, 就沉睡,等待唤醒; 如果是读锁, 就尝试循环获取锁, 改变计数器, 并修改自己的计数器
###Syncf.ullTryAcquireShared方法
/**
* 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()) {
//走到这里说明出问题了. 下吗都是修正逻辑
// 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) {// 加完1 后还是0 . 说明在加 之前计数器就达到了最大值
firstReader = current; //此时
firstReaderHoldCount = 1; //此时当前线程的计数器 置位1 , ?????
} else if (firstReader == current) {
firstReaderHoldCount++; //当前线程就是第一个获取读锁的线程
} else {
// 当前线程不是获取锁的线程, 下面就是获取当前线程的计数器加1
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;
}
}
}
###Sync.doAcquireShared
上面获取读锁失败后悔接入这个方法, 获取读锁失败, 说明写锁存在,
/**
* Acquires in shared uninterruptible mode.
* @param arg the acquire argument
*/
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED); //当前线程节点加载链表尾部
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); //获取当前节点的前一个节点
if (p == head) {
int r = tryAcquireShared(arg); //尝试获取读锁, 获取成功返回1 ,获取失败返回-1
if (r >= 0) {
setHeadAndPropagate(node, r); //获取成功, 把当前节点设为头部, 并且唤醒下一个读节点.
p.next = null; // help GC
if (interrupted)
selfInterrupt(); //中断本线程
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node); //这里只有failed 为true才会执行, 但是只有中断线程才会failed是true
//cancelAcquire 中会移除当前节点, 并唤醒下一个节点
}
}
readerShouldBlock方法有差异:** readerShouldBlock方法的注释说: 如果当前线程请求读锁, 返回true. 否则阻塞
NonfairSync.readerShouldBlock
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();
}
//链表第二位存在, 并且是写锁, 才返回true
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
FairSync.readerShouldBlock
hasQueuedPredecessors 方法 如果当前线程不是链表第二位, 或者链表第二位为null, 则返回true, 否则false
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
###读锁的释放 releaseShared
- 先tryReleaseShared 释放, 释放成功返回true, 释放失败返回false
- 成功后进入doReleaseShared方法, 方法内部如果head节点为SIGNAL状态就改变状态成0 并唤醒下一个节点, 如果head节点是0 就直接改成PROPAGATE, 需要传递唤醒后面的节点
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { //tryReleaseShared 释放成功这个方法才会返回值, 否则会一直循环, 返回true说明所有的读锁都已经释放了
doReleaseShared(); // 这里是所有读锁都释放完后的操作, 里面后有唤醒下一个线程的方法
return true;
}
return false;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) { //当前线程就是第一个获取读锁的线程
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1) // 当前线程只是重入了一次读锁
firstReader = null; // 直接清空当前线程
else
firstReaderHoldCount--; // 当前线程计数器减1
} 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; // 获取当前线程的计数器 减去1
}
for (;;) { // 开始循环来 减去state计数器的值
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; //返回读锁是否全部清空, true 就是全部清空
}
}
###内部类 Sync
继承了AbstractQueuedSynchronizer
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;