java并发编程之美 笔记
读写锁ReentrantReadWritelock
结构
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
//内部维护了一个读锁和写锁
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class NonfairSync extends Sync { }
static final class FairSync extends Sync { }
//读锁: shared锁
public static class ReadLock implements Lock, java.io.Serializable {}
//写锁: exclusive(独占)锁
public static class WriteLock implements Lock, java.io.Serializable {}
}
Sync
AQS只维护了一个状态state,但是读写锁需要维护读和写两个状态; ReentrantReadWriteLock巧妙的运用了
- state的
高16位
表示读状态即可以获取读锁
的次数(可以允许多个线程同时持有锁),
-低16位
表示写锁
可重入次数;
假设读锁允许重入7次, 写锁允许持有5次,那么state值为
00000000 00000111 00000000 00000101 = 458757
//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
static final int SHARED_SHIFT = 16;
//即2^16 : 00000000 00000001 00000000 00000000
// shareCount+SHARED_UNIT 组成state的高16位
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
//读锁与写锁的最大值都为即2^16 - 1
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
//即2^16 - 1 ; 00000000 00000000 11111111 1111111
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
//使用state高16位表示读锁次数
static int sharedCount(int c) {
// 00000000 00000111 00000000 00000101
// 右移动16位为
// 00000000 00000000 00000000 00000111 = 7
return c >>> SHARED_SHIFT;
}
static int exclusiveCount(int c) {
// 00000000 00000111 00000000 00000101 & 00000000 00000000 11111111 1111111
// c前16位为0,只保留后16位数:
// 00000000 00000000 00000000 00000101 = 5
return c & EXCLUSIVE_MASK;
}
}
- 重入
- 读线程在获取了读锁后还可以获取读锁;
- 写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
- 锁降级
- 允许从
写入锁降级为读取锁
,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。反之,则不允许。
- 允许从
写锁
获取写锁
//java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
public void lock() {
//1.调用AQS的方法--内部调用 2.Sync.tηrAcquire()
sync.acquire(1);
}
//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
//2.
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
//c != 0 ,表示读锁或者写锁已经被某个线程获取
if (c != 0) {
// w==0 说明有线程获取了读锁,但是没有线程持有写锁, 需要将锁“升级” 不允许,
// 已有线程持有了写锁,但不是当前线程,不允许.
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//执行到此的逻辑为: w != 0 && current == getExclusiveOwnerThread() 即当前线程持有写锁
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 更新state
setState(c + acquires);
return true;
}
//执行到此逻辑为c == 0; 即第一个持有锁的线程
if (writerShouldBlock() || //3. 若返回false,则尝试执行后续cas操作,若为true,则直接返回false;
!compareAndSetState(c, c + acquires)) //cas更新
return false;
setExclusiveOwnerThread(current);
return true;
}
3.writerShouldBlock()
由子类FairSync,NonfairSync实现,它有两种实现逻辑:
非公平锁
: 直接返回false
,即不阻塞,直接执行后续的cas操作公平锁
: 则需要判断当前线程是否为AQS等待队列中的第一个
.
//NonfairSync
final boolean writerShouldBlock() {
return false;
}
//FairSync
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
释放写锁
//java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
public void unlock() {
//1.调用AQS的release()方法--内部调用 2.Sync.tryRelease()
sync.release(1);
}
//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
protected final boolean tryRelease(int releases) {
//getExclusiveOwnerThread() == Thread.currentThread();
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//当一个线程获取写锁时,读锁的状态肯定为0, 所以这里没有考虑state的高16位
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
// 如采写锁可重入值为 0则释放锁,否则 只是简单地更新状态值
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
读锁
获取读锁
//java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock
public void lock() {
//1.调用AQS.acquireShared
sync.acquireShared(1);
}
//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquireShared(int arg) {
//2.由子类实现Sync
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
//2. java.util.concurrent.locks.ReentrantReadWriteLock.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
//记录每个线程持有的read锁个数
static final class HoldCounter {
int count = 0;
final long tid = getThreadId(Thread.currentThread());
}
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
private transient ThreadLocalHoldCounter readHolds;
//记录最后一个获取读锁的线程对应的HoldCounter
private transient HoldCounter cachedHoldCounter;
//记录第一个持有读锁的线程
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
//获取共享所入口--STARTER
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);
//尝试获取读锁,
//readerShouldBlock():
if (!readerShouldBlock() && //3.
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {// cas操作更新state
if (r == 0) {
//第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
//第一个获取读锁的线程----重入
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
//从ThreadLocal中获取当前线程对应的HoldCounter,并设置到cachedHoldCounter变量
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
//持有读锁++
rh.count++;
}
return 1;
}
//4. 类似tryAcquireShared,但是是自旋获取
return fullTryAcquireShared(current);
}
}
//3.
//3.1 NonfairSync
final boolean readerShouldBlock() {
//由AQS实现: 判断head.next是否为独占锁,如果是返回true
return apparentlyFirstQueuedIsExclusive();
}
//3.2 FairSync
final boolean readerShouldBlock() {
//判断head.next.thread 是否为当前线程,如果不是 返回true
return hasQueuedPredecessors();
}