bilibili-Java并发学习笔记16 AQS 之 ReentrantReadWriteLock
基于 java 1.8.0
P48_可重入读写锁底层源码分析及思想探究
// ReadWriteLock 使用示例
package new_package.thread.p45;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.IntStream;
public class ReadWriteLockTest {
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void method1() {
try {
readWriteLock.readLock().lock();
System.out.println("method1");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
public void method2() {
try {
readWriteLock.writeLock().lock();
System.out.println("method2");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadWriteLockTest demo = new ReadWriteLockTest();
IntStream.range(0, 10).forEach(k -> new Thread(() -> {
demo.method2();
}).start());
}
}
- 公平锁与非公平锁
类似 ReentrantLock ,在构造器中指定是否为公平锁,默认非公平模式;
// 默认非公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 指定为公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
/** 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;
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
// 关于同步器
/**
* ReentrantReadWriteLock 的内部类,同步器的实现
* 子类有公平版本和非公平版本
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
///
}
/**
* 非公平版本的 Sync
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
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();
}
}
/**
* 公平版本的 Sync
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
// 关于读写锁实现
/**
* ReentrantReadWriteLock 的内部类
* The lock returned by method {@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 the outer lock object
* @throws NullPointerException if the lock is null
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// ...
}
/**
* ReentrantReadWriteLock 的内部类
* 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;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// ...
}
- 读锁的上锁
readWriteLock.readLock().lock();
// 实现
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
// 尝试获取共享锁
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. 如果另一个线程持有写锁,则失败。
* 2. 否则,此线程符合 lock wrt state 的条件,
* 因此询问它是否应该因为队列策略而阻塞。
* 如果没有,尝试通过大小写状态和更新计数来授予。
* 注意,step不检查可重入获取,它被推迟到完整版本,
* 以避免在更典型的不可重入情况下检查保留计数。
* 3. 如果步骤2失败是因为线程明显不合格、CAS失败或计数饱和,
* 则使用完整的重试循环链到版本。
*/
Thread current = Thread.currentThread();
int c = getState();
// 校验是否有独占锁
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) {
// 共享锁的占有数不为0
// 第一个获取到此共享锁的线程是本线程
firstReaderHoldCount++;
} else {
// 共享锁的占有数不为0 ,且 firstReader 不是当前线程
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);
}
// int 类型占 4 byte,占 32 bit (一半就是 16 bit)
static final int SHARED_SHIFT = 16;
// 1 左移 16 位 :00000000 00000001 00000000 00000000
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
// (1 左移 16 位) -1 :00000000 00000000 11111111 11111111
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/**
* 返回以count表示的共享保留数
* state 无逻辑右移 16 位,即 state 的高16位
*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/**
* 返回以count表示的独占保留数
* state & 00000000 00000000 11111111 11111111 即:state 的低16位
*/
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// << 表示左移,不分正负数,低位补0;
// >> 表示右移,如果该数为正,则高位补0,若为负数,则高位补1;
// >>> 表示无符号右移,也叫逻辑右移,即无论该数为正负,都是高位补0
// Fair version of Sync
final boolean readerShouldBlock() {
// 等待队列中是否还有前置节点
return hasQueuedPredecessors();
}
// Nonfair version of Sync
final boolean readerShouldBlock() {
//
return apparentlyFirstQueuedIsExclusive();
}
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
- 写锁的上锁
readWriteLock.writeLock().lock();
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
// 尝试获取独占锁
// 若获取失败,则加入等待队列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// Sync in ReentrantReadWriteLock 的实现
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. 如果读计数非零或写入计数非零且所有者是不同的线程,则失败。
* 2. 如果计数饱和,则失败。(只有当count已非零时才会发生这种情况。)
* 3. 否则,如果这个线程是可重入的获取或队列策略允许的话,它就有资格被锁定。如果是,请更新状态并设置所有者。
*/
Thread current = Thread.currentThread();
// state 的状态
int c = getState();
// 独占锁数量
int w = exclusiveCount(c);
//
if (c != 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;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
P49_可重入读写锁的共享锁释放源码解析
- 读锁的释放
readWriteLock.readLock().unlock();
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
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--;
} 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;
}
}
- 写锁的释放
readWriteLock.writeLock().unlock();
public void unlock() {
sync.release(1);
}
// AQS
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
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;
}