ReentrantReadWriteLock
读锁:就是用于读互斥区中保护的变量
写锁:就是用于写互斥区中保护的变量
读操作 是不需要上锁的,写需要上锁
适用于读多写少的场景,读锁可以并发,写锁与其他锁互斥。
主要属性和构造器
public class ReentrantReadWriteLock implements ReadWriteLock {
// 读锁对象
private final ReentrantReadWriteLock.ReadLock readerLock;
// 写锁对象
private final ReentrantReadWriteLock.WriteLock writerLock;
// 同步器
final Sync sync;
// 默认构造器创建了非公平锁
public ReentrantReadWriteLock() {
this(false);
}
// 根据fair变量,来选择创建不同的锁:公平锁 FairSync 和非公平锁 NonfairSync
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; }
}
接口:主要用于获取读锁写锁
public interface ReadWriteLock {
// 用于获取读锁
Lock readLock();
// 用于获取写锁
Lock writeLock();
}
内部类
abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class NonfairSync extends Sync {}
static final class FairSync extends Sync {}
public static class ReadLock implements Lock, java.io.Serializable{}
public static class WriteLock implements Lock, java.io.Serializable {}
FairSync
公平锁
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
hasQueuedPredecessors() 方法,就是看AQS的阻塞队列里是否有其他线程在等待,如果有就去排队。
NofairSync
非公平锁
final boolean writerShouldBlock() {
return false; // 写线程拥有是false
}
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
读线程 apparentlyFirstQueuedIsExclusive()方法,不应该让写线程饥饿,非公平,不管前面是否有人排队都去抢。
有写锁在排队的抢矿下 去排队 : R->W->R
sync类
读锁可以多个线程同时持有,写锁只允许一个线程持有,读锁(共享锁)写锁(互斥锁),AQS中state变量分割为 高16位低16位,高16位表示读锁,低16位表示写锁
abstract static class Sync extends AbstractQueuedSynchronizer {
//简单的位运算
static final int SHARED_SHIFT = 16; //高16位表示读锁
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
//最大读锁数量
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
//左移16位 -1 后16位 1
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** 获取 shared 共享锁 读锁 的线程数量*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** 获取 exclusive 排他 写锁 的线程数量 */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/*** 用于每个线程读取保持计数的计数器。 维护为ThreadLocal; 缓存在cachedHoldCounter */
static final class HoldCounter {
int count = 0;
final long tid = getThreadId(Thread.currentThread());
}
//继承ThreadLocal 重写initialValue 方法,调用时初始化 HoldCounter计数器
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
//ThreadLocal 对象
private transient ThreadLocalHoldCounter readHolds;
//最后一个要成功获取的线程的持有计数
private transient HoldCounter cachedHoldCounter;
//保存了 第一个读线程
private transient Thread firstReader = null;
//保存此锁线程获取到第一个的读多数量
private transient int firstReaderHoldCount;
Sync() {
//初始化
readHolds = new ThreadLocalHoldCounter();
// 确保readhold的可见性
setState(getState());
}
}
tryAcquire方法
//写锁的获取流程
protected final boolean tryAcquire(int acquires) {
//获取当前线程
Thread current = Thread.currentThread();
//c 获取当前状态
int c = getState();
//互斥锁数量
int w = exclusiveCount(c);
if (c != 0) {
//当前不是写锁 或者 当前线程不是写锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//写锁 重入 写锁保存在低16位
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
// 当前线程是否应该获取写锁,CAS抢锁
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
//获取写锁成功 将当前线程标位 获取写锁的线程对象
setExclusiveOwnerThread(current);
return true;
}
tryRelase
//释放写锁
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())//没有获取到写锁
throw new IllegalMonitorStateException();
// 释放完毕后,写锁状态是否为0(锁重入),因为此时计算的不是当前state,是nextc
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
//设置 state变量
setState(nextc);
//返回 true 的情况下,有AQS来完成后续唤醒操作
return free;
}
tryAcquireShared、fullTryAcquireShared方法
//tryAcquireShared获取读锁的流程获取写锁的流程
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);
if (!readerShouldBlock() &&//子类判断是否要阻塞
r < MAX_COUNT &&//是否溢出
compareAndSetState(c, c + SHARED_UNIT)) {//CAS 增加高16位的读锁数量
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
//当前获取读锁的线程是一个线程 锁重入
firstReaderHoldCount++;
} else {
//当前不是第一个读线程,将获取读锁的次数保存在ThreadLocal中
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);
}
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {//有写锁, 当前获取到的写锁线程不是,当前线程
if (getExclusiveOwnerThread() != current)
return -1;
} else if (readerShouldBlock()) {//是否需要阻塞
// 当前线程是第一个获取到的 读锁线程
if (firstReader == current) {
} else {//获取当前线程记录读锁重入次数的 HoldCounter 对象
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)//当前读锁 重入次数为0,表示没有获取锁 返回-1
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)//读锁获取次数 溢出 抛出异常
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {//CAS 操作 增加
if (sharedCount(c) == 0) {//下边这些操作 和 trAcquire 方法中 一样
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) {//当前线程是第一个获取到读锁的线程
if (firstReaderHoldCount == 1)//当前重入次数为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) {//当前线程释放之后 ThreadLocal里不需要它了
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {//CAS 释放高16位
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;//为0的情况下为无锁状态,由AQS来唤醒
}
}
一个state分为高16低16,高表示读,低表示写,在进行写时,保证写线程不饥饿有没有写锁 有写锁去排队,默认是非公平的。