一、前言
在Java
并发包中常用的锁(如:ReentrantLock
),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。
相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock
能够提供比排他锁更好的并发性和吞吐量。
二、ReentrantReadWriteLock
1、ReentrantReadWriteLock类包含三个核心变量:
- readerLock:读锁。
- writerLock:写锁。
- sync:可以为公平锁FairSync 或 非公平锁NonfairSync。
2、ReentrantReadWriteLock类的构造函数执行以下几件事情:
- 新建锁对象赋予ReentrantReadWriteLock的sync对象。
- 将ReentrantReadWriteLock对象作为this参数创建读锁ReadLock。
- 将ReentrantReadWriteLock对象作为this参数创建写锁WriteLock。
- 在writerLock和ReadLock构造函数中将ReentrantReadWriteLock的sync对象赋值为自身的sync对象,读写锁的操作其实用的就是ReentrantReadWriteLock的sync对象。
// ReentrantReadWriteLock本身不提供加锁服务,只负责提供读锁和写锁
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock() {
this(false);
}
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 int getReadLockCount() {
return sync.getReadLockCount();
}
// 当前线程的写锁计数(当前线程必须占有锁)
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
// 当前线程的读锁计数
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
// 获取所有在SyncQueue中排队的写线程
protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
// 获取所有在SyncQueue中排队的读线程
protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
... ...
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET); // tid在Thread类中非volatile
}
private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset
(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
}
3、ReadLock
- ReadLock的构造函数入参为ReentrantReadWriteLock对象,通过将ReentrantReadWriteLock对象的sync对象赋值给ReadLock的Sync。
- ReadLock的lock和unlock操作都通过sync对象来实现加锁和解锁。
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() { // 加读锁
sync.acquireShared(1);
}
public void lockInterruptibly() throws InterruptedException { // 加读锁(可被中断)
sync.acquireSharedInterruptibly(1);
}
public boolean tryLock() { // 尝试加读锁
return sync.tryReadLock();
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException { // 加读锁(在timeOut内等锁)
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void unlock() { // 释放读锁
sync.releaseShared(1);
}
public Condition newCondition() { // 抛出不支持的条件异常
throw new UnsupportedOperationException();
}
public String toString() { // 返回标识此锁的字符串及其锁定状态
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
4、WriteLock
- WriteLock的构造函数入参为ReentrantReadWriteLock对象,通过将ReentrantReadWriteLock对象的sync对象赋值给ReadLock的Sync。
- WriteLock的lock和unlock操作都通过sync对象来实现加锁和解锁。
public static class WriteLock implements Lock, java.io.Serializable {
private final Sync sync;
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() { // 加写锁
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException { // 加写锁(可被中断)
sync.acquireInterruptibly(1);
}
public boolean tryLock( ) { // 尝试加写锁
return sync.tryWriteLock();
}
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { // 加写锁(在timeOut内等锁)
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() { // 释放写锁
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public String toString() { // 返回标识此锁的字符串及其lock状态
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
5、Sync
- 公平锁FairSync和非公平锁NonfairSync属于ReentrantReadWriteLock内部定义类,继承自Sync类。
- Sync类继承自AbstractQueuedSynchronizer类,Sync类有一些核心的变量已经加注释。
- AQS的state变量32位分开高16位为读状态,低16位为写状态。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() { // 写线程永远可以抢锁
return false;
}
final boolean readerShouldBlock() { // SyncQueue排队的第一个节点(head.next)为写节点占锁时必须排队
return apparentlyFirstQueuedIsExclusive();
}
}
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() { // SyncQueue中下个待唤醒节点不是当前线程时必须排队
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() { // SyncQueue中下个待唤醒节点不是当前线程时必须排队
return hasQueuedPredecessors();
}
}
public final boolean hasQueuedPredecessors() {
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());
}
static final class Node {
// 正在等待的共享锁
static final Node SHARED = new Node();
// 正在等待的独占锁
static final Node EXCLUSIVE = null;
// 等待状态取消
static final int CANCELLED = 1;
// 等待状态唤醒
static final int SIGNAL = -1;
// 等待状态条件
static final int CONDITION = -2;
// 无条件传播
static final int PROPAGATE = -3;
// 等待状态
volatile int waitStatus;
// 前驱节点
volatile Node prev;
// 后驱节点
volatile Node next;
volatile Thread thread;
// 链接到等待条件的下一个节点
Node nextWaiter;
// 如果节点在共享模式下等待,则返回true
final boolean isShared() {
return nextWaiter == SHARED;
}
// 返回上一个节点,如果为null则抛出NullPointerException。
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // 用于初始头部和共享标记
}
Node(Thread thread, Node mode) { // 由addWaiter模式使用
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // 由条件使用
this.waitStatus = waitStatus;
this.thread = thread;
}
}
核心类Sync,,这个类小伙伴们可以多花点时间研究下。
读写状态的设计
读写锁同样依赖自定义同步器来实现同步功能,而读写状态就是其同步器的同步状态。回想ReentrantLock中自定义同步器的实现,同步状态表示锁被一个线程重复获取的次数,而读写锁的自定义同步器需要在同步状态(一个整型变量)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。
如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁是将变量切分成了两个部分,高16位表示读,低16位表示写,划分方式如图所示。
如图所示,当前同步状态表示一个线程已经获取了写锁,且重进入了两次,同时也连续获取了两次读锁。读写锁是如何迅速的确定读和写各自的状态呢?答案是通过位运算。假设当前同步状态值为S,写状态等于 S & 0x0000FFFF(将高16位全部抹去),读状态等于 S >>> 16(无符号补0右移16位)。当写状态增加1时,等于S + 1,当读状态增加1时,等于S + (1 << 16),也就是S + 0x00010000。
根据状态的划分能得出一个推论:S不等于0时,当写状态(S & 0x0000FFFF)等于0时,则读状态(S >>> 16)大于0,即读锁已被获取。
abstract static class Sync extends AbstractQueuedSynchronizer {
static final int SHARED_SHIFT = 16; // state高16位为读锁计数,state低16位为写锁计数
static final int SHARED_UNIT = (1 << SHARED_SHIFT); // 读锁计数 + 1
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; // 读(写)锁计数 <= 2^16 - 1
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; // 写锁计数 = state & (2^16 - 1)
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // 确保readHolds的可见性
}
// return 锁状态(锁计数)
final int getCount() { return getState(); }
// 总的读锁计数
final int getReadLockCount() {
return sharedCount(getState());
}
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
// 当前线程的写锁计数(当前线程必须占有锁)
final int getWriteHoldCount() {
return isHeldExclusively() ? exclusiveCount(getState()) : 0;
}
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// 当前线程的读锁计数
final int getReadHoldCount() {
if (getReadLockCount() == 0)
return 0;
Thread current = Thread.currentThread();
if (firstReader == current)
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
return rh.count;
int count = readHolds.get().count;
if (count == 0) readHolds.remove();
return count;
}
private transient ThreadLocalHoldCounter readHolds; // 当前线程的读锁计数
private transient HoldCounter cachedHoldCounter; // 缓存的线程读锁计数
private transient Thread firstReader = null; // 首个读线程
private transient int firstReaderHoldCount; // 首个读线程的读锁计数
static final class HoldCounter {
int count = 0;
// tid在Thread类中非volatile
// Thread.getId -> UNSAFE.getLongVolatile(Thread.currentThread(), Thread.class.getDeclaredField("tid"))
final long tid = getThreadId(Thread.currentThread());
}
static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter(); // {0, currentThreadId}
}
}
// 尝试取写锁
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState(); /*记录state*/
int w = exclusiveCount(c); // 写锁计数w
if (c != 0) {// 读线程未释放锁 || 当前线程不是锁的独占者
if (w == 0 || current != getExclusiveOwnerThread())
return false; // 取锁失败
// 当前线程已占有锁(Reentrant)
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
setState(c + acquires); // 更新锁状态,写锁计数++
return true; // 成功取锁(已占有锁)
}
// state == 0
if (writerShouldBlock() || // false(NonfairSync)|| hasQueuedPredecessors(FairSync)
!compareAndSetState(c, c + acquires)) /*CAS设置state += acquires*/
// CAS(state)失败
return false; // 取锁失败
// CAS(state)成功
setExclusiveOwnerThread(current); // 设置当前线程为锁的独占者
return true; // 成功取锁
}
// 尝试抢写锁,不进行writerShouldBlock判断
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != 0) {
int w = exclusiveCount(c); // 写锁计数w
// 读线程未释放锁 || 当前线程不是锁的独占者
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 当前线程已占有锁(Reentrant)
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
if (!compareAndSetState(c, c + 1)) // CAS设置state += 1
// CAS(state)失败
return false; // 抢锁失败
// CAS(state)成功
setExclusiveOwnerThread(current);
return true; // 抢锁成功
}
// 尝试取读锁
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState(); /*记录state*/
// 写线程未释放锁 && 未释放锁的写线程非当前线程(读写线程可为同一线程)
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
return -1; // 取锁失败
int r = sharedCount(c); // 读锁计数r
if (!readerShouldBlock() && // apparentlyFirstQueuedIsExclusive(NonfairSync)|| hasQueuedPredecessors(FairSync)
r < MAX_COUNT && // r未超过阈值
compareAndSetState(c, c + SHARED_UNIT)) { /*CAS设置state += 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)) // 缓存为空 || 缓存的不是当前线程的读锁计数
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0) // 缓存的是当前线程的读锁计数,而当前线程的读锁计数在上次release时被删除
readHolds.set(rh);
rh.count++;
}
return 1; // 成功取锁
}
// CAS(state)失败
return fullTryAcquireShared(current);
}
// 不断尝试取读锁,直到取锁失败(写线程占有锁 || 当前线程的读锁计数为0) || 成功取锁
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
// 当前线程的读锁计数不为0 && CAS(state)失败将回到此处
int c = getState(); /*记录state*/
if (exclusiveCount(c) != 0) { // 写线程未释放锁
if (getExclusiveOwnerThread() != current) // 当前线程不是锁的独占者
return -1;// 取锁失败
} else if (readerShouldBlock()) {
if (firstReader == current) {
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0) // 当前线程的读锁计数为0
readHolds.remove(); // 在线程局部变量中删除当前线程的读锁计数
}
}
if (rh.count == 0) // 当前线程的读锁计数为0
return -1; // 应排队取锁
// 继续尝试取锁
}
}
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) { /*CAS设置state += SHARED_UNIT*/
// CAS(state)成功
if (sharedCount(c) == 0) { // 首个读线程
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; // 成功取锁
}
// CAS(state)失败
}
}
// 尝试抢读锁,不进行readerShouldBlock判断
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
// CAS(state)失败将回到此处
int c = getState(); /*记录state*/
// 写线程未释放锁 && 未释放锁的写线程非当前线程(读写线程可为同一线程)
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
return false; // 抢锁失败
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) { /*CAS设置state += 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))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++; // 当前线程的读锁计数(缓存的线程读锁计数)++
}
return true; // 成功抢锁
}
// CAS(state)失败
}
}
// 尝试释放写锁
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively()) // 当前线程未占有锁
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0; // 写锁计数是否为0
if (free) // 可释放锁
setExclusiveOwnerThread(null); // 锁的独占者置空
setState(nextc); // 更新锁状态
return free;
}
// 尝试释放读锁
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 (;;) {
// CAS(state)失败将回到此处
int c = getState(); /*记录state*/
int nextc = c - SHARED_UNIT; // 读锁计数--
if (compareAndSetState(c, nextc)) /*CAS设置state = nextc*/
// CAS(state)成功
return nextc == 0;
// CAS(state)失败
}
}
... ...
}
下一篇 中篇主要来讲解讲解ReentrantReadWriteLock
的ReadLock
的加锁和减锁过程:
源码解读之(五)ReentrantReadWriteLock(中)